########################################
# Define two connections as we want DDL to use its own connection
# in order to keep DDL statistics counting out of the way
# of the SPJ testing
########################################
connect (spj,localhost,root,,test);
connect (ddl,localhost,root,,test);

select @@session.optimizer_switch;

connection spj;
# Save old mysqld counter values.
create temporary table server_counts_at_startup
       select * from performance_schema.global_status 
       where variable_name in 
       ('Ndb_pruned_scan_count',
        'Ndb_sorted_scan_count',
        'Ndb_pushed_queries_defined',
        'Ndb_pushed_queries_dropped');

##############
# Test start

--error 0,1193
set @save_debug = @@global.debug;
set @save_ndb_join_pushdown = @@session.ndb_join_pushdown;
set ndb_join_pushdown = true;

connection ddl;
create table t1 (
  a int not null,
  b int not null,
  c int not null,
  d int not null,
  primary key (`a`,`b`)
) engine=ndbcluster
partition by key() partitions 8;

connection spj;
insert into t1 values
(1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4),
(1,2,5,1), (1,3,1,2), (1,4,2,3),
(2,1,3,4), (2,3,4,5), (2,4,5,1),
(3,1,1,2), (3,2,2,3), (3,4,3,4),
(4,1,4,5), (4,2,5,1), (4,3,1,2);

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

# Check that new JSON explain format is also handled:
SET explain_json_format_version = 1;
explain format=JSON
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;
SET explain_json_format_version = DEFAULT;

# Check that we do not push an operation if this prevents us from using
# 'join buffer'.
explain
select straight_join count(*) 
from t1 as x1 
join t1 as x2 on x1.d > x2.a + 1000 
join t1 as x3 on x1.c=x3.a and x1.d=x3.b;
select straight_join count(*) 
from t1 as x1 
join t1 as x2 on x1.d > x2.a + 1000 
join t1 as x3 on x1.c=x3.a and x1.d=x3.b;

# Check that we do not push an operation if this prevents us from using
# 'join buffer'.
explain select *
from t1 as x1 
join t1 as x2 on x1.a=1 and x1.c=x2.a and x1.d=x2.b 
join t1 as x3 
join t1 as x4 where x4.a=x3.c and x4.b=x1.d;
--sorted_result
select * 
from t1 as x1 
join t1 as x2 on x1.a=1 and x1.c=x2.a and x1.d=x2.b 
join t1 as x3 
join t1 as x4 where x4.a=x3.c and x4.b=x1.d;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.b and t2.b = t1.c;
--sorted_result
select *
from t1
left join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
where t1.a = 1 and t1.b = 1;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
where t1.a = 1 and t1.b = 1;

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b;

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
left join t1 as t3 on t3.a = t2.a and t3.b = t2.b;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
left join t1 as t3 on t3.a = t2.a and t3.b = t2.b;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.b and t2.b = t1.c
left join t1 as t3 on t3.a = t2.a and t3.b = t2.b;
--sorted_result
select *
from t1
left join t1 as t2 on t2.a = t1.b and t2.b = t1.c
left join t1 as t3 on t3.a = t2.a and t3.b = t2.b;

set ndb_join_pushdown=true;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

################################################################
# Bug#13901890 SQL NODE CRASHES DURING INSERT SELECT
#
# Incorrect lifetime handling for NdbQuery objects where
# the root operation was a 'const' lookup operation.
#
# 'virtual handler::index_read_idx_map()' was incorectly 
# implemented by ha_ndbcluster, such that it failed to 
# 'close' the table when the single 'const' row has been read.
# Neither was it registered as 'open' by using the ::ha_index_init().
# (Called ha_ndbcluster::index_init() directly)
# This resulted in that NdbQuery::close() was never called
# on these 'const' SPJ queries. Instead NdbTransaction end 
# forcefully whiped them away by calling NdbQuery::release().
# However, as there still was dangling pointer refs to 
# them from ha_ndbcluster::m_active_query, we may later refer
# them and crash!
#
#  - Same query as above.
#  - Added explict table locks as cleanup of these is one 
#    (of several?) way to cause released NdbQuery objects to
#    be refered.
################################################################

# LOCK'ed tables invokes the same code path as executing
# an 'INSERT... SELECT' inside a procedure invoked from a trigger.
# ... and is a much simpler testcase..... 
LOCK TABLES t1 read, t1 as t2 read;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

#Returns empty result set
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

#Returns a single row
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 3 and t1.b = 3;
UNLOCK TABLES;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3
order by t1.c;
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3
order by t1.c;

set ndb_join_pushdown=false;
--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p0 pX p5 pX
explain
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 2 and t1.b = 3;

set ndb_join_pushdown=true;
explain
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;

set ndb_join_pushdown=false;
explain
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;
select *
from t1
left join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.a = 1 and t1.b = 1;

## Join as 't1 ALL' -> 't2 RANGE' -> 't3 EQ_REF'
## Possibly joinable starting with 't2 - RANGE' as root.
## However t3's join condition 't3.a = t1.c' refers t1 which is
## outside the scope of current queryplan. The equality set 
## should be consulted in order to replace 't1.c' with 't2.a'
## inside the scope
set ndb_join_pushdown=true;
explain
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t1.c and t3.b = t2.b;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t1.c and t3.b = t2.b;

## Join as 'x ALL' -> 'y ALL' -> 'z EQ_REF'
## As Scan vs. scan is not pushable, only y,z is pushed
## However join cond on z refer x which is a
## (pseudo constant) paramValue wrt. the pushed join.
## As we have a dependency on previous rows these 
## should not be join cached (ref. HA_PUSH_BLOCK_JOINCACHE)
explain
select straight_join *
  from (t1 as x cross join t1 as y)
     join t1 as z on z.a=x.a and z.b=y.b;
--sorted_result
select straight_join *
  from (t1 as x cross join t1 as y)
     join t1 as z on z.a=x.a and z.b=y.b;


## Some variants of the above where t3 has a join conditions in t1
## where t1 is outside scope of pushed join (as above). However, in
## these tests t3 is also linked with t2 through another join condition.
## This makes t3 join pushable by specifying the value of t1.c as a
## paramValue()
explain
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0 and t2.b = t1.c
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b;
--sorted_result
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0 and t2.b = t1.c
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b;

--replace_column 10 # 11 #
explain
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0 and t2.b = t1.c
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b
where t1.a=1 and t1.d=1;
--sorted_result
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0 and t2.b = t1.c
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b
where t1.a=1 and t1.d=1;

explain
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b;
--sorted_result
select *
from t1
  straight_join t1 as t2 on t2.a = t1.b+0
  straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b;


## Create a non-ndb table used as a tool to force part of
## a query to be non-pushable.
connection ddl;
create table t1_myisam (
  a int not null,
  b int not null,
  c int not null,
  d int not null,
  primary key (`a`,`b`)
) engine=myisam;

connection spj;
insert into t1_myisam values
(1,1,1,1), (2,2,1,1), (3,3,1,1), (4,4,1,1);


## Optimizer will use the equality set to replace 't2.a' 
## in the term 't3.a = t2.a' with 't1.c' (as 't2.a = t1.c').
## Furthermore the MyIsam table t1 is const table optimized making
## 't1.c' a const_item. This constant value has not yet been materialized
## into the key_buffer when the definition for the linked query is
## created. However, it is always available through the 
## Field defining the KEY_PART of this JT_EQ_REF.
##

set ndb_join_pushdown=true;

explain
select *
from t1_myisam as t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
where t1.a=2 and t1.b=2;
--sorted_result
select *
from t1_myisam as t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
where t1.a=2 and t1.b=2;

## Bug#28898811 INCORRECTLY REJECT JOIN TO BE PUSHED DOWN
##
## .. also served to detect (also see ndb_endian.test):
## Bug#29010641 FAILS TO HANDLE DIFFERENT ENDIANNESS FORMATS IN PUSHED JOIN KEYS
##
## Tables not beings considered in the join pushdown analysis,
## e.g. a table not being a ndb table, where also incorrectly
## excluded as a table which could be referred in the join conditions
## from a pushed child table (on .. t3.b = t1.b <-, below)
##
explain
select *
from t1_myisam as t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.b and t3.b = t1.b;
--sorted_result
select *
from t1_myisam as t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.b and t3.b = t1.b;

connection ddl;
drop table t1_myisam;

#
# Test scans with filter. These should be pushed as linked operations
# where the root operation is a scan *with* a (pushed) filter and a 
# primary key lookup child operation.
#

connection spj;
set ndb_join_pushdown=true;

# Table scan
--replace_column 10 # 11 #
explain select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.d = 3;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
where t1.d = 3;

# Ordered index scan
--replace_column 10 # 11 #
explain select *
from t1 
join t1 as t2 on t2.a = t1.c and t2.b = t1.d 
where t1.a > 2 and t1.d = 3;
--sorted_result
select * 
from t1 
join t1 as t2 on t2.a = t1.c and t2.b = t1.d 
where t1.a > 2 and t1.d = 3;

# Sorted scan of ordered index.
--replace_column 10 # 11 #
explain select *
from t1 join t1 as t2 on t2.a = t1.c and t2.b = t1.d 
where t1.d = 3 
order by t1.a;
--sorted_result
select * 
from t1 join t1 as t2 on t2.a = t1.c and t2.b = t1.d 
where t1.d = 3 
order by t1.a;

#
# Test index scan w/ equal-bounds (low == high)
# NOTE: There used to be temp restriction of not allowing ordered 
# index scans to be pushed. (Has later been lifted)
# SQL stmt. are therefore written with pushable JT_REFs from table 2 -> 
#
set ndb_join_pushdown=true;
explain
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.c
left join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;
--sorted_result
select *
from t1
left join t1 as t2 on t2.a = t1.c
left join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;

set ndb_join_pushdown=false;
explain
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;
--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;

explain
select *
from t1
left join t1 as t2 on t2.a = t1.c
left join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;
--sorted_result
select *
from t1
left join t1 as t2 on t2.a = t1.c
left join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t1.a = 1 and t1.b = 1;

# JT_REF as root operations is now supported as pushed joins
set ndb_join_pushdown=true;
explain
select *
from t1 as t2
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t2.a = 1;
--sorted_result
select *
from t1 as t2
join t1 as t3 on t3.a = t2.c and t3.b = t2.d
where t2.a = 1;

# Test multiparent pushed joins where it is not possible
# to find a single common parent by using the equality set
#
# NOTE: We should take care to join the multiparent linked
# table on field refs. not also being refered from other join expr.
# as this will make them candidates for equality set replacement.
#
set ndb_join_pushdown=true;

# t3 refer both t1,t2 as parrent.
# t1 should be identifed as a grandparent available
# through its child t2.
explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t2.c and t3.b = t1.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t2.c and t3.b = t1.c;

# t4 is pushable iff we force an artificial parental dependency between t2 & t3.
explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

# t3 is a child of t2 and grandchild of t1
# t4 is a child of t3 and grandchild of t2
explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t2.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t2.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

# t3 is a child of t2 and grandchild of t1
# t4 is a child of t3 and grandgrandchild of t1
explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t2.d
 join t1 as t4 on t4.a = t3.c and t4.b = t1.d;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t2.d
 join t1 as t4 on t4.a = t3.c and t4.b = t1.d;

# Some testcases where t4 is not directly pushable, but
# may be made pushable by equality set replacement.
#
# BEWARE: mysqld optimizer may do its own replacement
#    before ha_ndbcluster_push analyze the AQP. We therefore 
#    provide multiple similar testcases and hope that
#    some of them will trigger the replacement code in 
#    ha_ndbcluster_push :-o
explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.a and t4.b = t2.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.a and t4.b = t2.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.b and t4.b = t2.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.b and t4.b = t2.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.a;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.a;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.b;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t2.b;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t1.c and t4.b = t2.c;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t1.c and t4.b = t2.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t1.b;
--sorted_result
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 join t1 as t4 on t4.a = t3.c and t4.b = t1.b;

# Added more multidependency tests;
#

explain
select straight_join *
from t1
 join t1 as t2  on t2.a = t1.a and t2.b = t1.b
 join t1 as t2x on t2x.a = t2.c and t2x.b = t2.d
 join t1 as t3x on t3x.a = t1.c and t3x.b = t1.d
 join t1 as t4  on t4.a = t3x.c and t4.b = t2x.c;

explain
select straight_join *
from t1
 join t1 as t2  on t2.a = t1.a and t2.b = t1.b
 join t1 as t2x on t2x.a = t2.c and t2x.b = t2.d
 join t1 as t3  on t3.a = t1.c and t3.b = t1.d
 join t1 as t3x on t3x.a = t3.c and t3x.b = t3.d
 join t1 as t4  on t4.a = t3x.c and t4.b = t2x.c; 

explain
select straight_join *
from t1
 join t1 as t2  on t2.a = t1.a and t2.b = t1.b
 join t1 as t3  on t3.a = t1.c and t3.b = t1.d
 join t1 as t2x on t2x.a = t2.c and t2x.b = t2.d
 join t1 as t3x on t3x.a = t3.c and t3x.b = t3.d
 join t1 as t4  on t4.a = t3x.c and t4.b = t2x.c; 

# 't3' is not referred as ancestor and should not be
# included in the forced dependencies
# (Depends directly on 't1' and can be bushy wrt. to
#  the other tables)
explain
select straight_join *
from t1
 join t1 as t2  on t2.a = t1.a and t2.b = t1.b
 join t1 as t2x on t2x.a = t2.c and t2x.b = t2.d
 join t1 as t3  on t3.a = t1.c and t3.b = t1.d
 join t1 as t3x on t3x.a = t1.c and t3x.b = t1.d
 join t1 as t4  on t4.a = t3x.c and t4.b = t2x.c;

# 't3' is still independent - see comment above.
explain
select straight_join *
from t1
 join t1 as t2  on t2.a = t1.a and t2.b = t1.b
 join t1 as t2x on t2x.a = t2.c and t2x.b = t2.d
 join t1 as t3  on t3.a = t1.c and t3.b = t1.b
 join t1 as t3x on t3x.a = t1.c and t3x.b = t1.d
 join t1 as t4  on t4.a = t3x.c and t4.b = t2x.c;

## It should not be possible to force grandparent dependencies
## via a previously outer joined table:
explain
select straight_join *
from t1
 left join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 left join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 left join t1 as t3 on t3.a = t1.c and t3.b = t1.d
 left join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

explain
select straight_join *
from t1
 left join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.a
 left join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 left join t1 as t3 on t3.a = t1.a
 left join t1 as t4 on t4.a = t3.c and t4.b = t2.c;

explain
select straight_join *
from t1
 left join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 join t1 as t3 on t3.a = t1.a
 left join t1 as t4 on t4.a = t3.c;

explain
select straight_join *
from t1
 join t1 as t2 on t2.a = t1.a and t2.b = t1.b
 left join t1 as t3 on t3.a = t1.a
 left join t1 as t4 on t4.a = t3.c;

# Bug#16199028:
# Tescase where a too strict 'root' was checked:
# In these cases t4 was not pushed as it was incorrectly
# concluded that its grandparent ref of 't2' through 't3'
# introduced dependencies on the outer joined t1.
#
explain
select straight_join *
from
 ( t1 as t0 left join t1 as t1 on t1.a = t0.a and t1.b = t0.b
 )
 left join
 ( t1 as t2 join t1 as t3 on t3.a = t2.c and t3.b = t2.d
            join t1 as t4 on t4.a = t3.c and t4.b = t2.c
 )
 on t2.a = t1.a and t2.b = t1.b;

explain
select straight_join *
from
  t1 as x1
  left join 
  ( t1 as x2 join t1 as x3 on x3.a=x2.c
             join t1 as x4 on x4.a=x2.d
             join t1 as x5 on x5.a=x3.d and x5.b=x4.d
  )
  on x2.a=x1.c and x2.b=x1.c and 
     x3.b=x1.d and
     x4.b=x1.d;


# Bug#16198866:
# Additional tests where equality set [t1.d, t3.b, t4.d]
# propagation incorrectly allowed grandparent references
# to be allowed 'through' outer joins (t2):
#
# Test: don't allow t4 to propagate parent deps past 
# outer joined 't2' into t3.
# (As that would implicit cause t3 to depend on t2.)
#
explain
select straight_join * from
 (t1 left join t1 as t2 on t2.a = t1.c and t2.b = t1.d)
 inner join t1 as t3 on t3.a = t1.b and t3.b = t1.c
 left join t1 as t4 on t4.a = t2.c and t4.b = t1.c;

--sorted_result
select straight_join * from
 (t1 left join t1 as t2 on t2.a = t1.c and t2.b = t1.d)
 inner join t1 as t3 on t3.a = t1.b and t3.b = t1.c
 left join t1 as t4 on t4.a = t2.c and t4.b = t1.c;

# However, if t3 already depends on t2 (t3.a = t2.b)
# it *is* allowed as it will not introduce any new 
# t3 dependencies.
#
# Note: Both these two queries are fully pushable, but 
# the later will likely result in a better query plan.
#
explain
select straight_join * from
 (t1 left join t1 as t2 on t2.a = t1.c and t2.b = t1.d)
 inner join t1 as t3 on t3.a = t2.b and t3.b = t1.c
 left join t1 as t4 on t4.a = t2.c and t4.b = t1.c;

--sorted_result
select straight_join * from
 (t1 left join t1 as t2 on t2.a = t1.c and t2.b = t1.d)
 inner join t1 as t3 on t3.a = t2.b and t3.b = t1.c
 left join t1 as t4 on t4.a = t2.c and t4.b = t1.c;

# Test a combination of pushed table scan (x, y)
#  & pushed EQ-bound (indexScan) (z, t1)
# This used to give incorrect results with random result for last table (t1)
set ndb_join_pushdown=true;
explain
  select * from t1 x, t1 y, t1 z, t1 where 
    y.a=x.d and y.b=x.b and 
    z.a=y.d and 
    t1.a = z.d and t1.b=z.b;
--sorted_result
  select * from t1 x, t1 y, t1 z, t1 where 
    y.a=x.d and y.b=x.b and 
    z.a=y.d and 
    t1.a = z.d and t1.b=z.b;

# Pushed scanIndex() with (multi-)range:
explain
  select * from t1 x, t1 y where
    x.a <= 2 and
    y.a=x.d and y.b=x.b;
--sorted_result
  select * from t1 x, t1 y where
    x.a <= 2 and
    y.a=x.d and y.b=x.b;

explain
  select * from t1 x, t1 y where
    (x.a <= 2 or x.a > 3) and
    y.a=x.d and y.b=x.b;
--sorted_result
  select * from t1 x, t1 y where
    (x.a <= 2 or x.a > 3) and
    y.a=x.d and y.b=x.b;

# 'open' range:
--replace_column 10 # 11 #
explain
  select * from t1 x, t1 y where
    (x.a >= 2 or x.a < 3) and
    y.a=x.d and y.b=x.b;
--sorted_result
  select * from t1 x, t1 y where
    (x.a >= 2 or x.a < 3) and
    y.a=x.d and y.b=x.b;

# Combination of range and 'in' list
explain
  select * from t1 x, t1 y where
    (x.a <= 2 or x.a in (0,5,4)) and
    y.a=x.d and y.b=x.b;
--sorted_result
  select * from t1 x, t1 y where
    (x.a <= 2 or x.a in (0,5,4)) and
    y.a=x.d and y.b=x.b;

# Combination of range and 'in' list with exact match
# NOTE: Due to simplification in pushed mrr, exact matches are also
#       executed as range scans
explain
  select * from t1 x, t1 y where
    (x.a <= 2 or (x.a,x.b) in ((0,0),(5,0),(4,3))) and
    y.a=x.d and y.b=x.b;
--sorted_result
  select * from t1 x, t1 y where
    (x.a <= 2 or (x.a,x.b) in ((0,0),(5,0),(4,3))) and
    y.a=x.d and y.b=x.b;

# Test ORDER BY expressions
# If it is a 'simple' order, i.e all order by's are plain column refs
# to the first non-const table, the optimizer will (by heuristic) 
# make the first table 'ordered' beforing joining in the siblings.
# This may involve presorting of the first table into intermediate storage.
#
# This will make this (parent-) table  non-pushable as 
# read of rows to be filesorted will also prefetch rows from pushed child
# operands. These are not cached by the filesort buffer mechanisnm and are
# effectively lost.
#
# Non simple ordering will always writte entire resultset to temp.
# table and filesort that -> No extra push restrictions on these.
#
# Integrating pushed joins we either has to:
#  1)  find a suitable ordered index which we can create an ordered indexscan on 
#  (-> joinType() -> JT_NEXT, or type: 'index' w/ explain)
#  or:
# 2) Reject pushing of the this parent table.
#
# Comment1: As 'order by' correctness is part of what we want to test,
#           '--sorted_result' is *not* specified. Instead we aim at
#           specifying a deterministic sort ordering in order by list.
#
# Comment2: 't1.a, t1.b' is appended where required to the order by spec 
#           to get a deterministic sorting order wo/ '--sorted_result'
#           

#
# Bug #30338585
#    SPJ INTEGRATION: FAILS TO DETECT FILESORT OF A TABLE IN MIDDLE OF PUSHED JOIN
#
# Extracted from TPC-H Q16, which failed to detect that the first
# table in the query plan required a 'filesort', and thus should not
# have been pushed. That effectively voided the entire pushed join and
# caused poor performance. The correct query plan for Q16 would be
# to 'filesort' the first table, then push the join of the two preceeding
# tables.
#
# Below is a test case transformed to the test tables we normally use.
# Optimizer will decide to presort t1 into a temporary table before
# joining with t2. Thus the below query should not be pushed.
#

explain format=tree
select straight_join t1.b, count(distinct t2.b) as cnt
from t1
join t1 as t2 on t2.a = t1.c
group by t1.b
order by t1.b, cnt;

select straight_join t1.b, count(distinct t2.b) as cnt
from t1
join t1 as t2 on t2.a = t1.c
group by t1.b
order by t1.b, cnt;

# Remaining (Original) test cases for eliminating filesort'ed tables
# from a pushed join:

## Non-pushed join w/ 'simple order' on non_PK - Presorts parent table.
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.c,t1.d,
t1.a, t1.b;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.c,t1.d,
t1.a, t1.b;

## pushed join w/ non-'simple order' on non_PK - Need temp table + filesort
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.c,t2.d,
t1.a, t1.b;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.c,t2.d,
t1.a, t1.b;

## pushed join w/ 'simple order' on PK - Should use ordered index scan 
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a,t1.b;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a,t1.b;

## pushed join w/ non-'simple order' on PK - will need temp table + filesort 
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a,t2.b,
t1.a, t1.b;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a,t2.b,
t1.a, t1.b;

## Descending ordering on PK - use reversed ordered index scan
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a desc,t1.b desc;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a desc,t1.b desc;

## Simple-PK column in incorrect order, -> Presort parent table, (no-push)
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.b,t1.a;
#--sorted_result
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.b,t1.a;

## Explore other permutations of PK columns in ORDER BY clause
## Don't care about the results here....
# Subset of first part of PK -> ordered index scan
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.a;

# PK columns not including first part -> Presort parent table, (no-push)
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
order by t1.b;


## Similar tests for GROUP BY expression
## PK grouping (or subpart) may be optimized
## by ordered index access.
##
explain
select t1.a, t1.b, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.a, t1.b;
--sorted_result
select t1.a, t1.b, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.a, t1.b;

explain
select t1.a, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.a;
--sorted_result
select t1.a, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.a;

explain
select t1.b, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.b;
--sorted_result
select t1.b, count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
join t1 as t3 on t3.a = t2.a and t3.b = t2.b
group by t1.b;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p1 pX p2 pX
explain
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4 and t2.b=4
group by t2.c;
--sorted_result
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4 and t2.b=4
group by t2.c;

explain
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4
group by t2.c;
--sorted_result
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4
group by t2.c;

--replace_result p0,p1,p2,p3,p4,p5,p6,p7 pXYZ p1 pX p2 pX
explain
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4 and t2.b=4
group by t2.c order by t2.c;
--sorted_result
select t2.c, count(distinct t2.a)
from t1
join t1 as t2 on t1.a = t2.c and t1.b = t2.d
where t2.a = 4 and t2.b=4
group by t2.c order by t2.c;

connection ddl;
create table tx like t1;

connection spj;
insert into tx 
  select x1.a+x2.a*16, x1.b+x2.b*16, x1.c+x2.c*16, x1.d+x2.d*16 
    from t1 as x1 cross join t1 as x2;

# Test of outer join with scan child.
# This query should not be pushed. Doing so would produce lots of extra
# [<x1 row>.NULL] rows, since the x1.d=x2.d predicate cannot be pushed.
explain select count(*) from tx as x1 
  left join tx as x2 on x1.c=x2.a and x1.d=x2.d;
select count(*) from tx as x1 
  left join tx as x2 on x1.c=x2.a and x1.d=x2.d;

connection ddl;
drop table tx;

# Test bushy join with pruned scan.
connection ddl;
alter table t1 partition by key(a);

connection spj;

explain select count(*) from t1 
  join t1 as t2 on t2.a = t1.c 
  join t1 as t3 on t3.a = t1.d;
select count(*) from t1 
  join t1 as t2 on t2.a = t1.c 
  join t1 as t3 on t3.a = t1.d;

# Test bushy join with pruned scan and larger result set.

connection ddl;
CREATE TABLE tx (
  a int NOT NULL,
  PRIMARY KEY (`a`)
) comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
delete from t1;

insert into tx values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

insert into t1 select 1, x1.a * 10+x2.a, 1, 1 from tx as x1 cross join tx as x2;

--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

--replace_column 10 # 11 #
explain select count(*) from t1 as x1
  join t1 as x2 on x2.a = x1.c and x1.b < 2 
  join t1 as x3 on x3.a = x1.d;
select count(*) from t1 as x1
  join t1 as x2 on x2.a = x1.c and x1.b < 2 
  join t1 as x3 on x3.a = x1.d;

--error 0,1193
set global debug=@save_debug;

connection ddl;
drop table t1;
drop table tx;

# Test user defined partition not being pushed
#
# Note: User defined partitions are handled
#       by the SQL layer, and as such are unknown
#       to the NDB datanodes.
# 

connection spj;
create table t1 (
  a int not null,
  b int not null,
  c int not null,
  d int not null,
  primary key (`a`,`b`)
) engine=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
  partition by key(a);

connection spj;
insert into t1 values
(1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4),
(1,2,5,1), (1,3,1,2), (1,4,2,3),
(2,1,3,4), (2,3,4,5), (2,4,5,1),
(3,1,1,2), (3,2,2,3), (3,4,3,4),
(4,1,4,5), (4,2,5,1), (4,3,1,2);

# Only this query('partition by key') should be pushed
explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

connection ddl;
alter table t1 partition by hash(a);

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

connection ddl;
alter table t1 partition by list(a) (
  partition p1 values in (1),
  partition p2 values in (2),
  partition p3 values in (3),
  partition p4 values in (4)
);

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

connection ddl;
alter table t1 partition by range(a) partitions 4 (
  partition p1 values less than (0),
  partition p2 values less than (2),
  partition p3 values less than (4),
  partition p4 values less than (99999)
);

explain
select *
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

connection ddl;
drop table t1;

# pushed mrr does not yet handle multiple PK operations in same transaction
# Need 6.0 result handling stuff to simplify result handling
# *** join push is currently dissabled for these ****
#
connection ddl;
create table t1 (a int, b int, primary key(a) using hash) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1, 2);
insert into t1 values (2, 3);
insert into t1 values (3, 1);

set ndb_join_pushdown=true;

##
# In ps-protocol, server will adds calls to execute(Commit)
#   (these are optimized away by ndbapi, since there is nothing to commit)
#   and these generates a diff in execute-count
# To not have to investigate problem futher, I simply set autocommit=off
#   (and back further down where we don't track execute-count any longer)
# It would probably be good to changes these tests to instead use frazers new
#   ndbapi counters, and instead measure #round-trips
set autocommit=off;

explain
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b;
--source suite/ndb/include/ndb_init_execute_count.inc
--sorted_result
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b;
--source suite/ndb/include/ndb_execute_count.inc
--echo This should yield 3 executes (for now...buh)

set autocommit=on;

connection ddl;
drop table t1;

# Same case when there is an ordered index on PK
connection ddl;
create table t1 (a int, b int, primary key(a)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1, 2);
insert into t1 values (2, 3);
insert into t1 values (3, 1);

set ndb_join_pushdown=true;

##
# In ps-protocol, server will adds calls to execute(Commit)
#   (these are optimized away by ndbapi, since there is nothing to commit)
#   and these generates a diff in execute-count
# To not have to investigate problem futher, I simply set autocommit=off
#   (and back further down where we don't track execute-count any longer)
# It would probably be good to changes these tests to instead use frazers new
#   ndbapi counters, and instead measure #round-trips
set autocommit=off;

explain
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b;
--source suite/ndb/include/ndb_init_execute_count.inc
--sorted_result
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b;
--source suite/ndb/include/ndb_execute_count.inc
--echo This should yield 1 execute (but inefficient since it's based on scan)

set autocommit=on;

## Adding and 'order by ... desc' trigger the usage
## of QUICK_SELECT_DESC which somehow prepares a 
## pushed join as indexscan but ends up executing it as 
## primary key access. This (auto-) disables the pushed 
## join execution (EXPLAIN still says 'pushdown') which
## should test handling of this in ha_ndbcluster::index_read_pushed()

explain
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b
order by t1.a desc;
select *
from t1, t1 as t2
where t1.a in (1,3,5)
  and t2.a = t1.b
order by t1.a desc;


connection ddl;
drop table t1;

set ndb_join_pushdown=true;

connection ddl;
create table t1 (a int, b int, primary key(a)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t2 (c int, d int, primary key(c)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t3 (a3 int, b3 int, c3 int not null, d3 int not null,
 primary key(a3, b3)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t3_hash (a3 int, b3 int, c3 int not null, d3 int not null,
 primary key(a3, b3) using hash) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (0x1f, 0x2f);
insert into t1 values (0x2f, 0x3f);
insert into t1 values (0x3f, 0x1f);

insert into t2 values (0x1f, 0x2f);
insert into t2 values (0x2f, 0x3f);
insert into t2 values (0x3f, 0x1f);

insert into t3 values (0x1f, 0x2f, 1, 0x1f);
insert into t3 values (0x2f, 0x3f, 2, 0x2f);
insert into t3 values (0x3f, 0x1f, 3, 0x3f);

insert into t3_hash values (0x1f, 0x2f, 1, 0x1f);
insert into t3_hash values (0x2f, 0x3f, 2, 0x2f);
insert into t3_hash values (0x3f, 0x1f, 3, 0x3f);

explain
select * from t3 x, t3 y, t1 where y.a3=x.d3 and y.b3=x.b3 and t1.a = y.d3;
--sorted_result
select * from t3 x, t3 y, t1 where y.a3=x.d3 and y.b3=x.b3 and t1.a = y.d3;

explain
select *
from t3 x, t3 y, t3 z, t3 z2, t1
where y.a3=x.d3 and y.b3=x.b3 and
      z.a3=y.d3 and z.b3=y.b3 and
      z2.a3=z.d3 and z2.b3=z.b3 and
      t1.a = z2.d3;
--sorted_result
select *
from t3 x, t3 y, t3 z, t3 z2, t1
where y.a3=x.d3 and y.b3=x.b3 and
      z.a3=y.d3 and z.b3=y.b3 and
      z2.a3=z.d3 and z2.b3=z.b3 and
      t1.a = z2.d3;

# Table expressions wo/ parent-child linkage should *not* be executes as a pushed join:
--replace_column 10 # 11 #
explain
select straight_join * from t1 x, t1 y where y.a=0x1f and x.b = 0x1f;
select straight_join * from t1 x, t1 y where y.a=0x1f and x.b = 0x1f;

# NOTE: Due to constValue replacement in equality sets, query below are
# effectively the same as the one above. -> Don't push either
--replace_column 10 # 11 #
explain
select straight_join * from t1 x, t1 y where y.a=x.b and x.b = 0x1f;
select straight_join * from t1 x, t1 y where y.a=x.b and x.b = 0x1f;


# Tests usage of unique index
connection ddl;
create unique index t3_d3 on t3(d3); 
create unique index t3_d3 on t3_hash(d3);
commit;

connection spj;
# Use an unique key to lookup root in pushed join:
explain
  select * from t3 x, t3 y where x.d3=31 and y.a3=x.d3 and y.b3=x.b3;
  select * from t3 x, t3 y where x.d3=31 and y.a3=x.d3 and y.b3=x.b3;

# No data-found on unique key lookup root
explain
  select * from t3 x, t3 y where x.d3=0 and y.a3=x.d3 and y.b3=x.b3;
  select * from t3 x, t3 y where x.d3=0 and y.a3=x.d3 and y.b3=x.b3;

# Use an unique key to lookup joined child tables
explain
  select * from t1 x, t3 y where y.d3=x.b;
--sorted_result
  select * from t1 x, t3 y where y.d3=x.b;

# Unique index used both for root lookup and child linkage.
explain
  select * from t3 x, t3 y where x.d3=31 and y.d3=x.b3;
  select * from t3 x, t3 y where x.d3=31 and y.d3=x.b3;

# No data-found on unique key lookup child
explain
  select * from t3 x, t3 y where x.d3=31 and y.d3=x.c3;
  select * from t3 x, t3 y where x.d3=31 and y.d3=x.c3;

# 'index_merge' between PRIMARY and index t3.d3
# NOTE: currently unhandled
explain
  select * from t3 x, t3 y 
  where ((x.a3=0x2f and x.b3=0x3f) or x.d3=0x1f)
    and  (y.a3=x.d3 and y.b3=x.b3);
# No 'sorted_result' required as index merge itself sort on PK
 select * from t3 x, t3 y
 where ((x.a3=0x2f and x.b3=0x3f) or x.d3=0x1f)
   and  (y.a3=x.d3 and y.b3=x.b3);

explain
  select * from t3_hash x, t3_hash y
  where ((x.a3=0x2f and x.b3=0x3f) or x.d3=0x1f)
    and  (y.a3=x.d3 and y.b3=x.b3);
# No 'sorted_result' required as index merge itself sort on PK
  select * from t3_hash x, t3_hash y
  where ((x.a3=0x2f and x.b3=0x3f) or x.d3=0x1f)
    and  (y.a3=x.d3 and y.b3=x.b3);

# Any ordered index may also be used to scan a 'range'
explain
  select * from t3 x, t3 y where x.d3>=31 and y.d3=x.b3;
--sorted_result
  select * from t3 x, t3 y where x.d3>=31 and y.d3=x.b3;


# handle "null" key
insert into t1 values (0x4f, null);
--sorted_result
select * from t1 left join t1 as t2 on t2.a = t1.b;

### Test max number of pushable operations.

insert into t3 values (8,8,8,8);

# Unique lookups only.
explain select count(*) from t3 as x0
 join t3 as x1 on x0.b3=x1.d3 and x0.d3=8
 join t3 as x2 on x1.b3=x2.d3
 join t3 as x3 on x2.b3=x3.d3
 join t3 as x4 on x3.b3=x4.d3
 join t3 as x5 on x4.b3=x5.d3
 join t3 as x6 on x5.b3=x6.d3
 join t3 as x7 on x6.b3=x7.d3
 join t3 as x8 on x7.b3=x8.d3
 join t3 as x9 on x8.b3=x9.d3
 join t3 as x10 on x9.b3=x10.d3
 join t3 as x11 on x10.b3=x11.d3
 join t3 as x12 on x11.b3=x12.d3
 join t3 as x13 on x12.b3=x13.d3
 join t3 as x14 on x13.b3=x14.d3
 join t3 as x15 on x14.b3=x15.d3
 join t3 as x16 on x15.b3=x16.d3
 join t3 as x17 on x16.b3=x17.d3;

select count(*) from t3 as x0
 join t3 as x1 on x0.b3=x1.d3 and x0.d3=8
 join t3 as x2 on x1.b3=x2.d3
 join t3 as x3 on x2.b3=x3.d3
 join t3 as x4 on x3.b3=x4.d3
 join t3 as x5 on x4.b3=x5.d3
 join t3 as x6 on x5.b3=x6.d3
 join t3 as x7 on x6.b3=x7.d3
 join t3 as x8 on x7.b3=x8.d3
 join t3 as x9 on x8.b3=x9.d3
 join t3 as x10 on x9.b3=x10.d3
 join t3 as x11 on x10.b3=x11.d3
 join t3 as x12 on x11.b3=x12.d3
 join t3 as x13 on x12.b3=x13.d3
 join t3 as x14 on x13.b3=x14.d3
 join t3 as x15 on x14.b3=x15.d3
 join t3 as x16 on x15.b3=x16.d3
 join t3 as x17 on x16.b3=x17.d3;


# Max scans
explain select count(*) from t3 as x0
 join t3 as x1 on x0.c3=x1.a3
 join t3 as x2 on x1.c3=x2.a3
 join t3 as x3 on x2.c3=x3.a3
 join t3 as x4 on x3.c3=x4.a3
 join t3 as x5 on x4.c3=x5.a3
 join t3 as x6 on x5.c3=x6.a3
 join t3 as x7 on x6.c3=x7.a3
 join t3 as x8 on x7.c3=x8.a3
 join t3 as x9 on x8.c3=x9.a3
 join t3 as x10 on x9.c3=x10.a3
 join t3 as x11 on x10.c3=x11.a3
 join t3 as x12 on x11.c3=x12.a3
 join t3 as x13 on x12.c3=x13.a3
 join t3 as x14 on x13.c3=x14.a3
 join t3 as x15 on x14.c3=x15.a3
 join t3 as x16 on x15.c3=x16.a3
 join t3 as x17 on x16.c3=x17.a3
 join t3 as x18 on x17.c3=x18.a3
 join t3 as x19 on x18.c3=x19.a3
 join t3 as x20 on x19.c3=x20.a3
 join t3 as x21 on x20.c3=x21.a3
 join t3 as x22 on x21.c3=x22.a3
 join t3 as x23 on x22.c3=x23.a3
 join t3 as x24 on x23.c3=x24.a3
 join t3 as x25 on x24.c3=x25.a3
 join t3 as x26 on x25.c3=x26.a3
 join t3 as x27 on x26.c3=x27.a3
 join t3 as x28 on x27.c3=x28.a3
 join t3 as x29 on x28.c3=x29.a3
 join t3 as x30 on x29.c3=x30.a3
 join t3 as x31 on x30.c3=x31.a3
 join t3 as x32 on x31.c3=x32.a3
 join t3 as x33 on x32.c3=x33.a3;

select count(*) from t3 as x0
 join t3 as x1 on x0.c3=x1.a3
 join t3 as x2 on x1.c3=x2.a3
 join t3 as x3 on x2.c3=x3.a3
 join t3 as x4 on x3.c3=x4.a3
 join t3 as x5 on x4.c3=x5.a3
 join t3 as x6 on x5.c3=x6.a3
 join t3 as x7 on x6.c3=x7.a3
 join t3 as x8 on x7.c3=x8.a3
 join t3 as x9 on x8.c3=x9.a3
 join t3 as x10 on x9.c3=x10.a3
 join t3 as x11 on x10.c3=x11.a3
 join t3 as x12 on x11.c3=x12.a3
 join t3 as x13 on x12.c3=x13.a3
 join t3 as x14 on x13.c3=x14.a3
 join t3 as x15 on x14.c3=x15.a3
 join t3 as x16 on x15.c3=x16.a3
 join t3 as x17 on x16.c3=x17.a3
 join t3 as x18 on x17.c3=x18.a3
 join t3 as x19 on x18.c3=x19.a3
 join t3 as x20 on x19.c3=x20.a3
 join t3 as x21 on x20.c3=x21.a3
 join t3 as x22 on x21.c3=x22.a3
 join t3 as x23 on x22.c3=x23.a3
 join t3 as x24 on x23.c3=x24.a3
 join t3 as x25 on x24.c3=x25.a3
 join t3 as x26 on x25.c3=x26.a3
 join t3 as x27 on x26.c3=x27.a3
 join t3 as x28 on x27.c3=x28.a3
 join t3 as x29 on x28.c3=x29.a3
 join t3 as x30 on x29.c3=x30.a3
 join t3 as x31 on x30.c3=x31.a3
 join t3 as x32 on x31.c3=x32.a3
 join t3 as x33 on x32.c3=x33.a3;

#Mixed join
explain select count(*) from t3 as x0
 join t3 as x1 on x0.b3=x1.d3
 join t3 as x2 on x1.b3=x2.d3
 join t3 as x3 on x2.b3=x3.d3
 join t3 as x4 on x3.b3=x4.d3
 join t3 as x5 on x4.b3=x5.d3
 join t3 as x6 on x5.b3=x6.d3
 join t3 as x7 on x6.b3=x7.d3
 join t3 as x8 on x7.b3=x8.d3
 join t3 as x9 on x8.b3=x9.d3
 join t3 as x10 on x9.b3=x10.d3
 join t3 as x11 on x10.b3=x11.d3
 join t3 as x12 on x11.b3=x12.d3
 join t3 as x13 on x12.b3=x13.d3
 join t3 as x14 on x13.b3=x14.d3
 join t3 as x15 on x14.b3=x15.d3
 join t3 as x16 on x15.b3=x16.d3
 join t3 as x17 on x15.b3=x17.a3
 join t3 as x18 on x16.b3=x18.d3;

select count(*) from t3 as x0
 join t3 as x1 on x0.b3=x1.d3
 join t3 as x2 on x1.b3=x2.d3
 join t3 as x3 on x2.b3=x3.d3
 join t3 as x4 on x3.b3=x4.d3
 join t3 as x5 on x4.b3=x5.d3
 join t3 as x6 on x5.b3=x6.d3
 join t3 as x7 on x6.b3=x7.d3
 join t3 as x8 on x7.b3=x8.d3
 join t3 as x9 on x8.b3=x9.d3
 join t3 as x10 on x9.b3=x10.d3
 join t3 as x11 on x10.b3=x11.d3
 join t3 as x12 on x11.b3=x12.d3
 join t3 as x13 on x12.b3=x13.d3
 join t3 as x14 on x13.b3=x14.d3
 join t3 as x15 on x14.b3=x15.d3
 join t3 as x16 on x15.b3=x16.d3
 join t3 as x17 on x15.b3=x17.a3
 join t3 as x18 on x16.b3=x18.d3;

connection ddl;
drop table t1,t2,t3, t3_hash;

###############################
## Test Primary key and unique key defined 'out of order'
## wrt. the order in which columns was defined in 'create table' 

connection ddl;
create table t3 (a3 int, b3 int, c3 int, d3 int,
 primary key(b3, a3)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

create table t3_hash (a3 int, b3 int, c3 int, d3 int,
 primary key(b3,a3) using hash) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

create table t3_unq (pk int, a3 int not null, b3 int not null, c3 int, d3 int,
 primary key(pk) using hash, unique key(b3,a3) using hash) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t3 values (0x1f, 0x2f, 1, 0x1f);
insert into t3 values (0x2f, 0x3f, 2, 0x2f);
insert into t3 values (0x3f, 0x1f, 3, 0x3f);

insert into t3_hash values (0x1f, 0x2f, 1, 0x1f);
insert into t3_hash values (0x2f, 0x3f, 2, 0x2f);
insert into t3_hash values (0x3f, 0x1f, 3, 0x3f);

insert into t3_unq values (1001, 0x1f, 0x2f, 1, 0x1f);
insert into t3_unq values (1002, 0x2f, 0x3f, 2, 0x2f);
insert into t3_unq values (1003, 0x3f, 0x1f, 3, 0x3f);

## Table scans (ALL) as pushed root
explain
select * from t3 x, t3 y where y.a3=x.d3 and y.b3=x.b3;
--sorted_result
select * from t3 x, t3 y where y.a3=x.d3 and y.b3=x.b3;

explain
select * from t3_hash x, t3_hash y where y.a3=x.d3 and y.b3=x.b3;
--sorted_result
select * from t3_hash x, t3_hash y where y.a3=x.d3 and y.b3=x.b3;

explain
select * from t3_unq x, t3_unq y where y.a3=x.d3 and y.b3=x.b3;
--sorted_result
select * from t3_unq x, t3_unq y where y.a3=x.d3 and y.b3=x.b3;

## Lookup (eq_ref/const) as pushed root
explain
select * from t3 x, t3 y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;
select * from t3 x, t3 y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;

explain
select * from t3_hash x, t3_hash y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;
select * from t3_hash x, t3_hash y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;

explain
select * from t3_unq x, t3_unq y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;
select * from t3_unq x, t3_unq y where y.a3=x.d3 and y.b3=x.b3
  and x.a3=0x2f and x.b3=0x3f;

connection ddl;
drop table t3, t3_hash, t3_unq;

###########

connection ddl;
create table t3 (a3 int, b3 int, c3 int, d3 int,
 primary key(a3), unique key(d3)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t3 values (0x1f, 0x2f, 1, 0x1f);
insert into t3 values (0x2f, 0x3f, 2, 0x2f);
insert into t3 values (0x3f, 0x1f, 3, 0x3f);
insert into t3 values (0x4f, 0,    null, null);

explain
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.d3
 left outer join t3 as t3 on t3.a3 = t2.d3;
--sorted_result
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.d3
 left outer join t3 as t3 on t3.a3 = t2.d3;

## Test usage of nullable unique key column in where clause on pushed parent node
explain
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 = 47;
--sorted_result
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 = 47;

explain
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 >= 47;
--sorted_result
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 >= 47;

explain
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 is null;
--sorted_result
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 is null;

explain
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 is not null;
--sorted_result
select * from t3 as t1
 left outer join t3 as t2 on t2.d3 = t1.a3
 left outer join t3 as t3 on t3.a3 = t2.d3
 where t1.d3 is not null;

################################
# Bug#33451256 AbstractQueryPlan (AQP) return incorrect
#              access type to be used for a table.
#
# If the column(s) an unique index is specified over
# are nullable, _and_ the key contains a NULL value,
# multiple NULL-valued rows may still be returned from the UNIQUE index.
# (All the non-NULL columns are unique though)
#
# Note that the optimizer correctly set the access type to REF (-> non-unique)
# However, the AQP still decided it was 'unique' as all key values
# was specified.
#
# Note that none of the 4 test cases added for this bug should
# emit the Warning '1296 Prepared pushed join could not be executed'
# with the patch for this bug. (It does without the patch)

# Insert an additional NULL value, such that the unique index on column d3
# now has 2 null values - Should not fail.
insert into t3 values (0x5f, 0x5f, 4, null);

# Need a non-unique index
alter table t3 add index ix(b3);

###################################
# AQP incorrectly clasified 'where t1.d3 is null' as a
# single row lookup operation (Even if explain says 'REF').
#
# As pushdown of index scans with a lookup root is not supported,
# we could not push 't3 as t1' as a root in query below.
# (t2 join t3) was pushed though.
#
# Correctly classifying t1-access as a index access would have
# allowed all 3 tables to be pushed.

let $query1 =
select straight_join *
from t3 as t1
  left join t3 as t2 on t2.b3 = t1.a3
  left join t3 as t3 on t3.b3 = t2.d3
where t1.d3 is null;

eval explain $query1;
--sorted_result
eval $query1;

#################################
# The other way around, making t2 and t3 acccess an EQ_REF:
# t1 is still incorrectly believed to be a single row operation
#
# A pushed join was now prepared for the full 't1 join t2 join t3' -
# ... with t1 as single row lookup operation.
#
# At execution time it turns out that t1 had a NULL in its key,
# which required an index scan access type. Thus the prepared pushed join
# ends up being unsuitable, and is dropped from being executed

let $query2 =
select straight_join *
from t3 as t1
  left join t3 as t2 on t2.d3 = t1.a3
  left join t3 as t3 on t3.d3 = t2.d3
where t1.d3 is null;

eval explain $query2;
--sorted_result
eval $query2;


# The only time where the optimizer set up a REF access, and
# we still do a unique single row access against it, is when
# we are using a HASH index. Then there is no ordered index
# available for doing a range type access:

alter table t3 drop index d3;

# Note that a 'using hash' index will warn about doing full table scans
# if the key has NULL values
alter table t3 add unique key(d3) using hash;

######################################
# Use the same two queries a above, now with a redefined HASH index:
# t1 access will now either be a unique single row acces, if key
# has no NULLs, or a full table scan. Which of them we can't really
# know until execution time when the key values are known, unless
# they are a const-literal.
#
# The first one now fails to push t1 as root as it belived it was
# a lookup type operation with t2 & t3 as scan child.
#
# As the t1 key is constructed from 't1.d3 is null', we should be
# able to detect early that t1 will be accessed using a full table scan.
# Thus preparing a scan type pushed join for all 3 tables

eval explain $query1;
--sorted_result
eval $query1;

####################################
# The other query was, and still is, asuming t1 to be a single row lookup.
# Thus we may prepare a pushed lookup join for all 3 tables.
#
# However, as the t1 condition 't1.d3 is null' turns out to need a
# full table scan, the pushed join is rejected at execution time
#
# We should be able to detect at prepare time that the key contain
# a NULL value, thus needing a table scan.

eval explain $query2;
--sorted_result
eval $query2;

# Bug#33451256 ... end
###################################

connection ddl;
drop table t3;

####### Composite unique keys, 'const' is part of EQ_REF on child nodes ####

connection ddl;
create table t3 (a3 int not null, b3 int not null, c3 int, d3 int,
 primary key(a3), unique key(b3,d3), unique key(c3,b3), unique key(c3,d3)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t3 values (0x1f, 0x2f, 1,    0x1f);
insert into t3 values (0x2f, 0x3f, 2,    0x2f);
insert into t3 values (0x3f, 0x1f, 3,    0x3f);
insert into t3 values (0x40, 0,    null, null);
insert into t3 values (0x41, 0,    null, null);
insert into t3 values (0x42, 0,    4,    null);
insert into t3 values (0x43, 0,    null, 0x43);

## Baseline: Not pushed as only one of the columns in unique indexes are REF'ed
explain
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3;

## Extend query above with 'where <const cond>'
explain
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f;

--replace_column 10 # 11 #
explain
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.d3 = 0x2f;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.d3 = 0x2f;

explain
select straight_join * 
  from t3 as x join t3 as y on x.d3 = y.d3
  where y.b3 = 0x2f;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.d3 = y.d3
  where y.b3 = 0x2f;

explain
select straight_join * 
  from t3 as x join t3 as y on x.d3 = y.d3
  where y.b3 = 0x20+0x2f;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.d3 = y.d3
  where y.b3 = 0x20+0x2f;


## Not pushable as 'not null' is actually not a single const value
--replace_column 10 # 11 #
explain
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 is not null;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 is not null;

## Neither 'is null' pushable as uniqueness is not defined for null
## ... and null's are not present in the unique index
explain
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 is null;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 is null;

explain
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.b3 = 0;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.b3 = 0;

## As 'b3' is defined as 'not null', this query will optimized as 'Impossible WHERE' (No push)
explain
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.b3 is null;
--sorted_result
select straight_join * 
  from t3 as x join t3 as y on x.c3 = y.c3
  where y.b3 is null;

## Will break up query in 2 pushed joins.
## Last join (join t3 as y2) refer x1.c3 which will
## be handled as a constant paramValue wrt. scope of the 
## second pushed join.
explain
select straight_join * from
  t3 as x1
  join t3 as y1 on y1.b3 = x1.b3 and y1.d3 = x1.d3
  join t3 as x2 on x2.b3 = y1.b3+0
  join t3 as y2 on y2.b3 = x2.c3 and y2.d3 = x1.c3;
--sorted_result
select straight_join * from
  t3 as x1
  join t3 as y1 on y1.b3 = x1.b3 and y1.d3 = x1.d3
  join t3 as x2 on x2.b3 = y1.b3+0
  join t3 as y2 on y2.b3 = x2.c3 and y2.d3 = x1.c3;


###########################
### Prepared statments ####
###########################

prepare stmt1 from
'select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f';

#execute multiple times
execute stmt1;
execute stmt1;

# Execute after drop expected to fail
drop prepare stmt1;
--error 1243
execute stmt1;

# Multiple prepare of same stmt should silently discard prev prepared stmt
prepare stmt1 from
'select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f';
prepare stmt1 from
'select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f';
drop prepare stmt1;

#Prepare explain'ed statement and execute it
prepare stmt1 from
'explain select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = 0x2f';
execute stmt1;
execute stmt1;

#survives commit;
commit;
execute stmt1;

# Drop index used by query -> Query plan should change to unpushed join
connection ddl;
drop index b3 on t3;

connection spj;
--replace_column 10 # 11 #
execute stmt1;

# Then recreate it -> original query plan
connection ddl;
create unique index b3 on t3(b3,d3);

connection spj;
execute stmt1;
drop prepare stmt1;

### Prepared stmt with dynamic parameters ('?') ###
prepare stmt1 from
'explain select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = ?';

set @a=47;
execute stmt1 using @a;
set @a=0;
execute stmt1 using @a;
set @a=null;
execute stmt1 using @a;

prepare stmt1 from
'select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3
  where y.d3 = ?';

set @a=47;
execute stmt1 using @a;
set @a=0;
execute stmt1 using @a;
set @a=null;
execute stmt1 using @a;

prepare stmt1 from
'explain select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3 and x.d3 = y.d3
  where x.a3 = ?';

set @a=47;
execute stmt1 using @a;
set @a=0;
execute stmt1 using @a;
set @a=null;
execute stmt1 using @a;

prepare stmt1 from
'select straight_join * 
  from t3 as x join t3 as y on x.b3 = y.b3 and x.d3 = y.d3
  where x.a3 = ?';

set @a=47;
execute stmt1 using @a;
set @a=0;
execute stmt1 using @a;
set @a=null;
execute stmt1 using @a;

connection ddl;
drop table t3;

connection spj;
# Execute after table dropped should fail
set @a=47;
--error 1146
execute stmt1 using @a;

####################

# test index scan disguised as JT_ALL
connection ddl;
create table t1 (a int primary key, b int, c int, index(b,c)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1,null, 2);
insert into t1 values (2,1, null);
insert into t1 values (3,2,2);
insert into t1 values (4,null, 2);
insert into t1 values (5,1, null);
insert into t1 values (6,2,2);

set ndb_join_pushdown=false;

--sorted_result
select *
from t1
join t1 as t2 on (t2.b = t1.b or t2.b = t1.a)
join t1 as t3 on t3.a = t2.a
join t1 as t4 on t4.a = t3.b /* index scan disguised as JT_ALL, pushdown=off */;

set ndb_join_pushdown=true;

explain
select *
from t1
join t1 as t2 on (t2.b = t1.b or t2.b = t1.a)
join t1 as t3 on t3.a = t2.a
join t1 as t4 on t4.a = t3.b /* index scan disguised as JT_ALL, pushdown=on */;
--sorted_result
select *
from t1
join t1 as t2 on (t2.b = t1.b or t2.b = t1.a)
join t1 as t3 on t3.a = t2.a
join t1 as t4 on t4.a = t3.b /* index scan disguised as JT_ALL, pushdown=on */;

## Test subquery execution where 'Full scan on null key' strategy requires
## table scan execution in addition to the key lookup which was prepared
## as part of the pushed join NdbQuery
explain
select *
from t1 where b in 
  (select x.a from t1 as x join t1 as y on (y.a = x.b))
xor c > 5;
--sorted_result
select *
from t1 where b in 
  (select x.a from t1 as x join t1 as y on (y.a = x.b))
xor c > 5;

##############
## Subqueries with EQ_REFs in subquery containing an outer referrences
## to 't1.b' should not be pushed as outer referrences are outside
## the scope of our JOIN_TAB's
##############
--replace_column 10 # 11 #
explain
select t1.a, (select straight_join x.a from t1 as x join t1 as y on x.a=y.b where y.a = t1.b) from t1;
--sorted_result
select t1.a, (select straight_join x.a from t1 as x join t1 as y on x.a=y.b where y.a = t1.b) from t1;

connection ddl;
drop table t1;

# mixed engines

connection ddl;
create table t1 (a int primary key, b int) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t2 (a int primary key, b int) engine = myisam;

connection spj;
insert into t1 values(1,1), (2,2), (3,3), (4,4);
insert into t2 values(1,1), (2,2), (3,3), (4,4);

explain
select * from t1, t2, t1 as t3
where t2.a = t1.b
  and t3.a = t2.b /* mixed engines */;
--sorted_result
select * from t1, t2, t1 as t3
where t2.a = t1.b
  and t3.a = t2.b /* mixed engines */;

connection ddl;
drop table t1, t2;

# Tables with blob, but not in the selected columns:

connection ddl;
create table t1 (a int primary key, b int, c blob) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t2 (a int primary key, b int) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1,1, 'kalle');
insert into t1 values (2,1, 'kalle');
insert into t1 values (3,3, 'kalle');
insert into t1 values (4,1, 'kalle');

insert into t2 values (1,1);
insert into t2 values (2,1);
insert into t2 values (3,3);
insert into t2 values (4,1);

set ndb_join_pushdown=true;
explain
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t2.a = t1.b;
--sorted_result
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t2.a = t1.b;

explain
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t2.a = t1.b
  and t1.a = 2;
--sorted_result
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t2.a = t1.b
  and t1.a = 2;

explain
select t1.a, t1.b, t2.a, t2.b
from t1, t2
where t1.a = t2.b;
--sorted_result
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t2.a = t1.b;

explain
select t1.a, t1.b, t2.a, t2.b
from t1, t2
where t1.a = t2.b
  and t2.a = 3;
--sorted_result
select t1.a, t1.b, t2.a, t2.b 
from t1, t2
where t1.a = t2.b
  and t2.a = 3;

#
# result sets contain blob
#   i.e no push
explain
select *
from t1, t2
where t2.a = t1.b;
--sorted_result
select *
from t1, t2
where t2.a = t1.b;

explain
select *
from t1, t2
where t2.a = t1.b
  and t1.a = 2;
--sorted_result
select *
from t1, t2
where t2.a = t1.b
  and t1.a = 2;

explain
select *
from t1, t2
where t1.a = t2.b;
--sorted_result
select *
from t1, t2
where t2.a = t1.b;

explain
select *
from t1, t2
where t1.a = t2.b
  and t2.a = 3;
--sorted_result
select *
from t1, t2
where t1.a = t2.b
  and t2.a = 3;

connection ddl;
drop table t1, t2;

## Test usage of a constValue() as part of the EQ_REF key relating a child operation
## with its previous parents.
## All datatypes are tested in the section below
##
connection ddl;
  create table t3 (a3 int, b3 tinyint, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3="63";
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3="63";

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 tinyint unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 smallint, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 smallint unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 mediumint, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 mediumint unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 int, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 int unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 bigint, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 bigint unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=(60+3);

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 boolean, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0, 1, 0x1f);
  insert into t3 values (0x2f, 1, 2, 0x2f);
  insert into t3 values (0x3f, 0, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=1;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=1;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 float, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 2.71, 1, 0x1f);
  insert into t3 values (0x2f, 3.00, 2, 0x2f);
  insert into t3 values (0x3f, 0.50, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.0;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.0;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 float unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 2.71, 1, 0x1f);
  insert into t3 values (0x2f, 3.00, 2, 0x2f);
  insert into t3 values (0x3f, 0.50, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.0;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.0;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 double, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 2.71, 1, 0x1f);
  insert into t3 values (0x2f, 3.14, 2, 0x2f);
  insert into t3 values (0x3f, 0.50, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 double unsigned, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 2.71, 1, 0x1f);
  insert into t3 values (0x2f, 3.14, 2, 0x2f);
  insert into t3 values (0x3f, 0.50, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 decimal, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=63;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=63;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 decimal(12,4), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 2.71, 1, 0x1f);
  insert into t3 values (0x2f, 3.14, 2, 0x2f);
  insert into t3 values (0x3f, 0.50, 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3=3.14;

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 date, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, '1905-05-17', 1, 0x1f);
  insert into t3 values (0x2f, '2000-02-28', 2, 0x2f);
  insert into t3 values (0x3f, '2000-02-29', 3, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='2000-02-28';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='2000-02-28';

## Temp removed due to lack of DATETIME2 support
#connection ddl;
#  drop table t3;
#  create table t3 (a3 int, b3 datetime, c3 int not null, d3 int not null, 
#    primary key(a3,b3)) engine = ndb;
#connection spj;
#  insert into t3 values (0x1f, '1905-05-17 12:30:00', 1, 0x1f);
#  insert into t3 values (0x2f, '2000-02-28 23:59:00', 2, 0x2f);
#  insert into t3 values (0x3f, '2000-02-29 12:59:59', 2, 0x3f);
#  explain
#  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='2000-02-28 23:59';
#  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='2000-02-28 23:59';
#
#connection ddl;
#  drop table t3;
#  create table t3 (a3 int, b3 time, c3 int not null, d3 int not null, 
#    primary key(a3,b3)) engine = ndb;
#connection spj;
#  insert into t3 values (0x1f, '12:30:00', 1, 0x1f);
#  insert into t3 values (0x2f, '23:59:00', 2, 0x2f);
#  insert into t3 values (0x3f, '12:59:59', 2, 0x3f);
#  explain
#  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='23:59';
#  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='23:59';

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 char(16), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 'Ole', 1, 0x1f);
  insert into t3 values (0x2f, 'Dole', 2, 0x2f);
  insert into t3 values (0x3f, 'Doffen', 2, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 varchar(16), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 'Ole', 1, 0x1f);
  insert into t3 values (0x2f, 'Dole', 2, 0x2f);
  insert into t3 values (0x3f, 'Doffen', 2, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 varchar(512), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 'Ole', 1, 0x1f);
  insert into t3 values (0x2f, 'Dole', 2, 0x2f);
  insert into t3 values (0x3f, 'Doffen', 2, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';

connection ddl;
  drop table t3;
  create table t3 (a3 int, b3 binary(16), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 'Ole', 1, 0x1f);
  insert into t3 values (0x2f, 'Dole', 2, 0x2f);
  insert into t3 values (0x3f, 'Doffen', 2, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';

connection ddl;
  drop table t3;
    create table t3 (a3 int, b3 varbinary(16), c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
    comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
connection spj;
  insert into t3 values (0x1f, 'Ole', 1, 0x1f);
  insert into t3 values (0x2f, 'Dole', 2, 0x2f);
  insert into t3 values (0x3f, 'Doffen', 2, 0x3f);
  explain
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';
  select * from t3 x, t3 y where x.a3=0x2f and y.a3=x.d3 and y.b3='Dole';

connection ddl;
  drop table t3;


## Joins where the datatype of the EQ_REF columns are not identical
## should not be pushed
##
connection ddl;
  create table t3 (a3 int, b3 tinyint, c3 int not null, d3 int not null, 
    primary key(a3,b3)) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
  insert into t3 values (0x1f, 0x2f, 1, 0x1f);
  insert into t3 values (0x2f, 0x3f, 2, 0x2f);
  insert into t3 values (0x3f, 0x1f, 3, 0x3f);
  explain
  select * from t3 x, t3 y where y.a3=x.b3 and y.b3="63";
  select * from t3 x, t3 y where y.a3=x.b3 and y.b3="63";

connection ddl;
  drop table t3;


##
## Testing of varchar datatype as part of lookup key and index bounds.
## Need special attention due to the 'ShrinkVarchar' format used by mysqld.

connection ddl;
create table t3 (a3 varchar(16), b3 int, c3 int not null, d3 int not null, 
  primary key(a3,b3)) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t3 values ('Ole', 0x1f, 1, 0x1f);
insert into t3 values ('Dole', 0x2f, 2, 0x2f);
insert into t3 values ('Doffen', 0x3f, 2, 0x3f);

# Varchar is lookup key
explain
select * from t3 x, t3 y where x.a3='Dole' and x.b3=0x2f and y.a3=x.a3 and y.b3=x.d3;
select * from t3 x, t3 y where x.a3='Dole' and x.b3=0x2f and y.a3=x.a3 and y.b3=x.d3;

# Varchar as hi/low bound
explain
select * from t3 x, t3 y where x.a3='Dole' and y.a3=x.a3 and y.b3=x.d3;
select * from t3 x, t3 y where x.a3='Dole' and y.a3=x.a3 and y.b3=x.d3;

connection ddl;
drop table t3;

connection ddl;
create table t1 (k int primary key, b int) engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1,1), (2,1), (3,1), (4,1);

## Pushed join driven by a scan, with cached row lookups:
## (Note: We force the Scan to not be pushed as the parent op
## by making the join condition on t2 a non-FIELD_ITEM ('t1.b+0')
## As all column 'b' has the same value (1), the scan will refer 
## the same t2 (parent) row in every access. This will trigger the 
## row caching in join_read_key() where we eliminate redundant lookups
## where 'next row == current row'. In order to work for linked operations,
## the value and status for all linked tables should be kept unaltered.
explain
select *
from t1
  straight_join t1 as t2 on t2.k = t1.b+0
  straight_join t1 as t3 on t3.k = t2.b
  straight_join t1 as t4 on t4.k = t1.b;
--sorted_result
select *
from t1
  straight_join t1 as t2 on t2.k = t1.b+0
  straight_join t1 as t3 on t3.k = t2.b
  straight_join t1 as t4 on t4.k = t1.b;

## Similar example as above, except that access to 't2' is made
## a const table access
explain
select *
from t1
  straight_join t1 as t2 on t2.k = t1.b+0
  straight_join t1 as t3 on t3.k = t2.b
  straight_join t1 as t4 on t4.k = t1.b
where t2.k = 1;
--sorted_result
select *
from t1
  straight_join t1 as t2 on t2.k = t1.b+0
  straight_join t1 as t3 on t3.k = t2.b
  straight_join t1 as t4 on t4.k = t1.b
where t2.k = 1;

connection ddl;
drop table t1;

##
# Try with higher row-count to test batching/flow control
#
--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

connection ddl;
create table t1 (
  a int not null auto_increment,
  b char(255) not null,
  c int not null,
  d char(255) not null,
  primary key (`a`,`b`)
) engine=ndbcluster
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
let $1=1000;
disable_query_log;
while ($1)
{
 eval insert into t1(a,b,c,d) values
 ($1, 'a', $1, 'a'),($1, 'b', $1+1, 'b'),($1, 'c', $1-1, 'c');
 dec $1;
}
enable_query_log;

explain
select count(*)
from t1 
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;
select count(*)
from t1 
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;

explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;
select count(*)
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;

explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.c;
select count(*)
from t1
join t1 as t2 on t2.a = t1.c and t2.b = t1.d
join t1 as t3 on t3.a = t2.c;

connection ddl;
alter table t1 partition by key(a);

connection spj;
explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;
select count(*)
from t1
join t1 as t2 on t2.a = t1.c
join t1 as t3 on t3.a = t2.c and t3.b = t2.d;

connection ddl;
drop table t1;

--error 0,1193
set global debug=@save_debug;

# Pushed join accessing disk data.

connection ddl;
create logfile group lg1
add undofile 'undofile.dat'
initial_size 1m
undo_buffer_size = 1m
engine=ndb;

create tablespace ts1
add datafile 'datafile.dat'
use logfile group lg1
initial_size 6m
engine ndb;

create table t1 (a int not null, 
                 b int not null storage disk, 
       		 c int not null storage memory, 
		 primary key(a)) 
		 tablespace ts1 storage disk engine = ndb
 comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (10, 11, 11);
insert into t1 values (11, 12, 12);
insert into t1 values (12, 13, 13);

connection ddl;
create table t2 (a int not null, 
       	     	 b int not null, primary key(a)) engine = ndb
 comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t2 values (10, 11);
insert into t2 values (11, 12);
insert into t2 values (12, 13);

# Disk data in projection of first op.
explain select * from t1, t2 where t1.c = t2.a;
--sorted_result
select * from t1, t2 where t1.c = t2.a;

explain select * from t1, t2 where t1.a=11 and t1.c = t2.a;
select * from t1, t2 where t1.a=11 and t1.c = t2.a;

# Disk data in projection of second op.
explain select * from t2, t1 where t2.b = t1.a;
--sorted_result
select * from t2, t1 where t2.b = t1.a;

explain select * from t2, t1 where t2.a=11 and t2.b = t1.a;
select * from t2, t1 where t2.a=11 and t2.b = t1.a;

# Disk data in predicate but not in projection
explain select t1.a, t1.c, t2.a, t2.b from t1, t2 where t1.b = t2.a;
--sorted_result
select t1.a, t1.c, t2.a, t2.b from t1, t2 where t1.b = t2.a;

explain select t1.a, t1.c, t2.a, t2.b from t1, t2 where t1.a=11 and t1.b = t2.a;
select t1.a, t1.c, t2.a, t2.b from t1, t2 where t1.a=11 and t1.b = t2.a;

connection ddl;
drop table t1;
drop table t2;

alter tablespace ts1
drop datafile 'datafile.dat';

drop tablespace ts1;

drop logfile group lg1
engine ndb;
connection spj;

# Store old counter values.
connection ddl;
create temporary table old_count 
       select counter_name, sum(val) as val 
       from ndbinfo.counters 
       where block_name='DBSPJ' 
       group by counter_name;

connection ddl;
# Specify number of partition to be independent of configured #LDM's
create table t1 (a int not null, 
                 b int not null,
                 c int not null,
                 primary key(a)) 
                 engine = ndb
                 partition by key() partitions 8;

connection spj;
# We use key values that have the same representation in little and big endian.
# Otherwise, the numbers for local and remote reads may depend on endian-ness,
# since hashing is endian dependent.
insert into t1 values (1, 2, 2);
insert into t1 values (2, 3, 3);
insert into t1 values (3, 4, 4);

# Run some queries that should increment the counters.
select * from t1 t1, t1 t2 where t1.a = 2 and t2.a = t1.b; 

select count(*) from t1 t1, t1 t2 where t2.a = t1.b; 

select count(*) from t1 t1, t1 t2 where t1.a >= 2 and t2.a = t1.b; 


# Get new counter values.
connection ddl;
create temporary table new_count 
       select counter_name, sum(val) as val 
       from ndbinfo.counters 
       where block_name='DBSPJ' 
       group by counter_name;

# Compute the difference.
--sorted_result
select new_count.counter_name, new_count.val - old_count.val 
       from new_count, old_count 
       where new_count.counter_name = old_count.counter_name
       and new_count.counter_name <> 'LOCAL_READS_SENT'
       and new_count.counter_name <> 'REMOTE_READS_SENT';

select 'READS_SENT', sum(new_count.val - old_count.val) 
       from new_count, old_count 
       where new_count.counter_name = old_count.counter_name
       and (new_count.counter_name = 'LOCAL_READS_SENT'
       or new_count.counter_name = 'REMOTE_READS_SENT');

connection ddl;
drop table old_count;
drop table new_count;
drop table t1;

### Test that scan filters are used for pushed operations.

connection ddl;
create table t1 (
       a int primary key, 
       b int,
       c int) engine = ndb
 comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1, 2, 3);
insert into t1 values (2, 3, 4);
insert into t1 values (3, 4, 5);

# Find the total number of lookups issued by the SPJ blocks.
let $spj_lookups = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and (counter_name='LOCAL_READS_SENT' or counter_name='REMOTE_READS_SENT'), Value, 1);


# Root scan should give only one tuple if scan filter is pushed. 
# Therefore only one lookup on 'y'.
--replace_column 10 # 11 #
explain select * from t1 x, t1 y where x.b=y.a and x.c=4;

select * from t1 x, t1 y where x.b=y.a and x.c=4;

--disable_query_log
--eval select sum(val) - $spj_lookups as lookups from ndbinfo.counters where block_name='DBSPJ' and (counter_name='LOCAL_READS_SENT' or counter_name='REMOTE_READS_SENT')
--enable_query_log

# Lookup on y should only give one result tuple if filter is pushed.
# This should give 3 lookups on 'y' and 1 on 'z', 4 in all.
--replace_column 10 # 11 #
explain select * from t1 x, t1 y, t1 z where x.b=y.a and y.c=4 and y.b=z.a;

select * from t1 x, t1 y, t1 z where x.b=y.a and y.c=4 and y.b=z.a;

--disable_query_log
--eval select sum(val) - $spj_lookups as lookups from ndbinfo.counters where block_name='DBSPJ' and (counter_name='LOCAL_READS_SENT' or counter_name='REMOTE_READS_SENT')
--enable_query_log

connection ddl;
drop table t1;

# Test and server status variables (i.e. mysqld counters)

connection ddl;
create table t1(
       a int not null,
       b int not null,
       c int not null,
       primary key(a,b))
engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
partition by key (a);

connection spj;
insert into t1 values (10, 10, 11);
insert into t1 values (11, 11, 12);
insert into t1 values (12, 12, 13);

# First query against a new table causes an extra scan (of a dictionaty table??)
# so adding an extra scan here to make results from the following part easier
# to interpret.
select * from t1 t1, t1 t2 
      where t1.a = 10 and t1.b = 10 and 
      	     t2.a = t1.c and t2.b = t1.c; 

# Save old counter values.
# Save old mysqld counter values.
create temporary table server_counts
       select * from performance_schema.global_status 
       where variable_name in 
       ('Ndb_scan_count',
        'Ndb_pruned_scan_count',
        'Ndb_sorted_scan_count',
        'Ndb_pushed_queries_defined',
        'Ndb_pushed_queries_dropped',
	'Ndb_pushed_reads');

# Run some queries that should increment the counters.
# This query should push a single read.
select * from t1 t1, t1 t2 
      where t1.a = 11 and t1.b = 11 and 
      	     t2.a = t1.c and t2.b = t1.c; 

# This query should push a sorted scan (and three reads).
select * from t1 t1, t1 t2 
       where t2.a = t1.c and t2.b = t1.c
       order by t1.a; 

# This query should push a pruned scan (but pruning must be fixed for 
# pushed scans.)
select count(*) from t1 t1, t1 t2 
       where t1.a = 11 and 
       	     t2.a = t1.c and t2.b = t1.c; 

# Calculate the change in mysqld counters.
select new.variable_name, new.variable_value - old.variable_value
       from server_counts as old,
         performance_schema.global_status as new
       where new.variable_name = old.variable_name
       order by new.variable_name;

drop table server_counts;

connection ddl;
drop table t1;

# Test scan pruning 
connection ddl;
create table t1(
       d int not null,
       c int not null,
       a int not null,
       b int not null,
       primary key using hash (a,b))
engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
partition by key (a);

connection spj;
insert into t1(a,b,c,d) values (10, 10, 11, 11);
insert into t1(a,b,c,d) values (11, 11, 12, 12);
insert into t1(a,b,c,d) values (12, 12, 13, 13);

let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);

# Should give pruned scan.

connection ddl;
create index i1 on t1(c,a);

connection spj;

select count(*) from t1 t1, t1 t2 where t1.c = 12 and t1.a = 11 and t2.a = t1.d and t2.b = t1.d; 

connection ddl;
drop index i1 on t1;

connection spj;
--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

# Should give pruned scan. There is a one sided limit for t1.b, but this is
# after the partition key prefix.

connection ddl;
create index i2 on t1(a,b);

connection spj;
select count(*) from t1 t1, t1 t2 where t1.a = 11 and t1.b<13 and t2.a = t1.c and t2.b = t1.c; 

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

# Should give pruned scan. Upper and lower bounds for t1.a are the sane. 
select count(*) from t1 t1, t1 t2 where t1.a >= 12 and t1.a<=12 and t2.a = t1.c and t2.b = t1.c; 

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

# Should not give pruned scan. Upper and lower bounds for t1.a are different. 
select count(*) from t1 t1, t1 t2 where t1.a >= 11 and t1.a<=12 and t2.a = t1.c and t2.b = t1.c; 

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

# Should not give pruned scan. There will be two sets of bounds that have
# different distribution keys (t1.a=10 and t1.a=12). 
select count(*) from t1 t1, t1 t2 where (t1.a = 10 or t1.a=12) and t1.b<13 and t2.a = t1.c and t2.b = t1.c; 

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

# Should give pruned scan. There will be two sets of bounds, but they have the
# same distribution key.

select count(*) from t1 t1, t1 t2 where t1.a = 10 and (t1.b<11 or t1.b>11) and t2.a = t1.c and t2.b = t1.c; 

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

connection ddl;
drop table t1;

create table t2(
       d int not null,
       e int not null,
       f int not null,
       a int not null,
       b int not null,
       c int not null,
       primary key using hash (a,b,c))
engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
partition by key (b,a);

connection spj;
insert into t2(a,b,c,d,e,f) values (1, 2, 3, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (1, 2, 4, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (2, 3, 4, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (3, 4, 5, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (4, 5, 6, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (5, 6, 7, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (6, 7, 8, 1, 2, 3); 
insert into t2(a,b,c,d,e,f) values (7, 8, 9, 1, 2, 3); 

connection ddl;
create index i2_1 on t2(d, a, b, e);

connection spj;

# Should give pruned scan. The index prefix containing the distribution key
# has a single possible value.
select count(*) from t2 x, t2 y where x.d=1 and x.a=1 and x.b=2 and y.a=x.d and y.b=x.e and y.c=3;

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
let $old_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--enable_query_log

connection ddl;
drop index i2_1 on t2;
create index i2_3 on t2(a, d, b, e);

connection spj;

# Should give pruned scan. The index prefix containing the distribution key
# has a single possible value.

# Turn off condition_fanout_filter to keep "old" QEP
set optimizer_switch='condition_fanout_filter=off';
select count(*) from t2 x, t2 y where x.d=1 and x.a=1 and x.b=2 and y.a=x.d and y.b=x.e and y.c=3;

# Restore condition_fanout_filter to default value
set optimizer_switch='condition_fanout_filter=default';

--disable_query_log
let $new_pruned_scan_count = query_get_value(show status like 'Ndb_pruned_scan_count', Value, 1);
--eval select $new_pruned_scan_count - $old_pruned_scan_count as pruned_scan_count
--enable_query_log

connection ddl;
drop table t2;

connection ddl;
create table t1 (a binary(10) primary key, b binary(10) not null) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values ('\0123456789', '1234567890');
insert into t1 values ('1234567890', '\0123456789');

explain
select count(*)
from t1 join t1 as t2 on t2.a = t1.b
where t1.a = '\0123456789';
select count(*)
from t1 join t1 as t2 on t2.a = t1.b
where t1.a = '\0123456789';

connection ddl;
drop table t1;


# Tests for some bugfixes which have been cherry picked from 5.1 main
# Not necessarily test of SPJ functionality, but may test optimizer
# behaviour which we depend on when doing RQG testing
# We can remove these testcases when fixes - and propper MTR testcases -
# Have been merged from 5.1 main branch.

connection ddl;
create table t1 (pk int primary key, a int unique key) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1,10), (2,20), (3,30);

set ndb_join_pushdown = false;

# Bug#53334:
# Join should be optimized as 'Impossible On condition'
# ... *not* 'Impossible WHERE'

explain
select * from t1 as x right join t1 as y
  on x.pk = y.pk
 and x.pk = y.a
 and x.a = y.pk
where y.pk = 2;
select * from t1 as x right join t1 as y
  on x.pk = y.pk
 and x.pk = y.a
 and x.a = y.pk
where y.pk = 2;


set ndb_join_pushdown = true;

explain
select * from t1 as x right join t1 as y
  on x.pk = y.pk
 and x.pk = y.a
 and x.a = y.pk
where y.pk = 2;
select * from t1 as x right join t1 as y
  on x.pk = y.pk
 and x.pk = y.a
 and x.a = y.pk
where y.pk = 2;

connection ddl;
drop table t1;

#########################################
# Test section for scan-child operations
#########################################

# Test scan-lookup-scan query (see http://lists.mysql.com/commits/115164)

connection ddl;
create table t1 (pk int primary key, u int not null, a int, b int) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create index ix1 on t1(b,a);
      
connection spj;
insert into t1 values (0,1,10,20);
insert into t1 values (1,2,20,30);
insert into t1 values (2,3,30,40);

--replace_column 10 # 11 #
explain select * from t1 as x join t1 as y join t1 as z on x.u=y.pk and y.a=z.b;
--sorted_result
select * from t1 as x join t1 as y join t1 as z on x.u=y.pk and y.a=z.b;

connection ddl;
drop table t1;

# Test sorted scan where inner join eliminates all rows (known regression).
connection ddl;
create table t1 (pk int primary key, u int not null) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (0,-1), (1,-1), (2,-1), (3,-1), (4,-1), (5,-1), (6,-1), 
(7,-1), (8,-1), (9,-1), (10,-1), (11,-1), (12,-1), (13,-1), (14,-1), (15,-1), 
(16,-1), (17,-1), (18,-1), (19,-1), (20,-1), (21,-1), (22,-1), (23,-1), 
(24,-1), (25,-1), (26,-1), (27,-1), (28,-1), (29,-1), (30,-1), (31,-1), 
(32,-1), (33,-1), (34,-1), (35,-1), (36,-1), (37,-1), (38,-1), (39,-1), 
(40,-1), (41,-1), (42,-1), (43,-1), (44,-1), (45,-1), (46,-1), (47,-1), 
(48,-1), (49,-1), (50,-1), (51,-1), (52,-1), (53,-1), (54,-1), (55,-1), 
(56,-1), (57,-1), (58,-1), (59,-1), (60,-1), (61,-1), (62,-1), (63,-1), 
(64,-1), (65,-1), (66,-1), (67,-1), (68,-1), (69,-1), (70,-1), (71,-1), 
(72,-1), (73,-1), (74,-1), (75,-1), (76,-1), (77,-1), (78,-1), (79,-1), 
(80,-1), (81,-1), (82,-1), (83,-1), (84,-1), (85,-1), (86,-1), (87,-1), 
(88,-1), (89,-1), (90,-1), (91,-1), (92,-1), (93,-1), (94,-1), (95,-1), 
(96,-1), (97,-1), (98,-1), (99,-1), (100,-1), (101,-1), (102,-1), (103,-1), 
(104,-1), (105,-1), (106,-1), (107,-1), (108,-1), (109,-1), (110,-1), 
(111,-1), (112,-1), (113,-1), (114,-1), (115,-1), (116,-1), (117,-1), 
(118,-1), (119,-1), (120,-1), (121,-1), (122,-1), (123,-1), (124,-1), 
(125,-1), (126,-1), (127,-1), (128,-1), (129,-1), (130,-1), (131,-1), 
(132,-1), (133,-1), (134,-1), (135,-1), (136,-1), (137,-1), (138,-1), (139,-1);

--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

explain select * from t1 as x join t1 as y on x.u=y.pk order by(x.pk);
select * from t1 as x join t1 as y on x.u=y.pk order by(x.pk);

--error 0,1193
set global debug=@save_debug;

connection ddl;
drop table t1;

# Test query using "scan -> unique index lookup -> index scan".

connection ddl;
create table t1 (pk int primary key, u int not null, a int, b int) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create index ix1 on t1(b,a);
create unique index ix2 on t1(u);

connection spj;
insert into t1 values (0,0,10,10);
insert into t1 values (1,1,10,10);
insert into t1 values (2,2,10,10);
insert into t1 values (3,3,10,10);
insert into t1 values (4,4,10,10);
insert into t1 values (5,5,10,10);
insert into t1 values (6,6,10,10);
insert into t1 values (7,7,10,10);
insert into t1 values (8,8,10,10);
insert into t1 values (9,9,10,10);
insert into t1 values (10,10,10,10);
insert into t1 values (11,11,10,10);


explain select count(*) from t1 as x1 join t1 as x2 join t1 as x3
on x1.a=x2.u and x2.a = x3.b;

select count(*) from t1 as x1 join t1 as x2 join t1 as x3 
on x1.a=x2.u and x2.a = x3.b;

explain select count(*) from t1 as x1, t1 as x2, t1 as x3
where x1.u=x2.pk and x1.a=x3.b;

select count(*) from t1 as x1, t1 as x2, t1 as x3 
where x1.u=x2.pk and x1.a=x3.b;

# Regression test for commit http://lists.mysql.com/commits/116372
# (missing rows in left join query with multiple result batches).

insert into t1 values (12,12,20,10);

explain select count(*) from t1 as x1 left join t1 as x2 on x1.a=x2.b;
select count(*) from t1 as x1 left join t1 as x2 on x1.a=x2.b;
set ndb_join_pushdown=off;
select count(*) from t1 as x1 left join t1 as x2 on x1.a=x2.b;
set ndb_join_pushdown=on;

# Test left join with mix of scan and lookup.
explain select count(*) from t1 as x1
left join t1 as x2 on x1.u=x2.pk 
left join t1 as x3 on x2.a=x3.b;

select count(*) from t1 as x1 
left join t1 as x2 on x1.u=x2.pk 
left join t1 as x3 on x2.a=x3.b;
set ndb_join_pushdown=off;
select count(*) from t1 as x1 
left join t1 as x2 on x1.u=x2.pk 
left join t1 as x3 on x2.a=x3.b;
set ndb_join_pushdown=on;

explain select count(*) from t1 as x1
left join t1 as x2 on x1.u=x2.pk
left join t1 as x3 on x2.a=x3.b
left join t1 as x4 on x3.u=x4.pk
left join t1 as x5 on x4.a=x5.b;

select count(*) from t1 as x1
left join t1 as x2 on x1.u=x2.pk
left join t1 as x3 on x2.a=x3.b
left join t1 as x4 on x3.u=x4.pk
left join t1 as x5 on x4.a=x5.b;
set ndb_join_pushdown=off;
select count(*) from t1 as x1
left join t1 as x2 on x1.u=x2.pk
left join t1 as x3 on x2.a=x3.b
left join t1 as x4 on x3.u=x4.pk
left join t1 as x5 on x4.a=x5.b;
set ndb_join_pushdown=on;


############################
# Testcase for 'Got error 20002 'Unknown error code' from NDBCLUSTER'
# Caused by failure to identify AT_MULTI_PRIMARY_KEY as a lookup operation.
# This in turn caused a pushed 'lookup-scan' query to be produced - which we don't support

# Should not be pushed (lookup-scan query)
explain select count(*) from t1 as x1
 join t1 as x2 on x1.a=x2.b
 where x1.pk = 1 or x1.u=1;

select count(*) from t1 as x1
 join t1 as x2 on x1.a=x2.b
 where x1.pk = 1 or x1.u=1;

############################
# Testcase which forced us to ditch using the 'global cursor'
# on the NdbQuery result set from mysqld.
#
# As the global cursor will fool mysqld into handling the resultset
# as a result from a scan - n*lookup query, incorrect cardinality on the
# parent operation was perceived. Which caused extra null-joined outer rows
# to be emitted in this testcase.
#
# Refactored handler interface and SPJ API use subcursor on each operation
# which correctly preserves the dependency between the parent subscans 
# and its child(s).

--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

set ndb_join_pushdown=on;
explain
select straight_join * from t1 as table1
  left join 
   (t1 as table2  join t1 as table3 on table2.pk = table3.b)
 on table1.pk = table2.b;
--sorted_result
select straight_join * from t1 as table1
  left join 
   (t1 as table2  join t1 as table3 on table2.pk = table3.b)
 on table1.pk = table2.b;

--error 0,1193
set global debug=@save_debug;

#############
# Testcase for 'sledgehammer' fix for scan -> outer join scan:
# Pushing of outer joined has to be dissabled as incomplete child batches
# may cause the parent row to be returned multiple times:

# Push scan-scan when inner joined
explain select straight_join * from t1 as x1
  inner join t1 as x2 on x2.b = x1.a;

# Outer joined scans are not pushed.
explain select straight_join * from t1 as x1
  left join t1 as x2 on x2.b = x1.a;
explain select straight_join * from t1 as x1
  right join t1 as x2 on x2.b = x1.a;

# If there is a lookup operation(s) inbetween the scans
# pushing is disabled if any of these are outer joined

# inner joined lookups, push allowed
explain select straight_join * from
  t1 as x1 inner join
    (t1 as x2 inner join t1 as x3 on x3.b = x2.a)
  on x2.pk = x1.a;

# Even if x3 is inner joined with x2 (lookup)
# push is dissabled as x2 is outer joined with embedding scan operation
# which makes join relation between the scans on x1 & x3 an 'indirect' outer join
explain select straight_join * from
  t1 as x1 left join
    (t1 as x2 inner join t1 as x3 on x3.b = x2.a)
  on x2.pk = x1.a;

#############
# Test bushy-scans:
# These should be allowed to be executed in 'parallel', depending on
# only the root operation
#

explain select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;
set ndb_join_pushdown=off;
select straight_join count(*) from t1 as x1 
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;
set ndb_join_pushdown=on;
select straight_join count(*) from t1 as x1 
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;

# A really bushy scan - would take almost forever to execute if
# we had to force the child scan to be non-bushy (serialized by
# adding artificial parent dependencies)
# 
--replace_column 10 # 11 #
explain select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.a
  join t1 as x4 on x4.b = x1.a
  join t1 as x5 on x5.b = x1.a
  join t1 as x6 on x6.b = x1.a
  join t1 as x7 on x7.b = x1.a
where x3.a < x2.pk and x4.a < x3.pk; 

# set '64rows' in order to avoid to small batches which will
# cause all subscans to be repeated... and repeated... and

--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

select straight_join count(*) from t1 as x1 
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.a
  join t1 as x4 on x4.b = x1.a
  join t1 as x5 on x5.b = x1.a
  join t1 as x6 on x6.b = x1.a
  join t1 as x7 on x7.b = x1.a
where x3.a < x2.pk and x4.a < x3.pk; 

--error 0,1193
set global debug=@save_debug;

#############
# If we have an outer join, we can't create an artificial dep. 'through' the outer join.
# In this case the child scan can't be part of the pushed query.
#
explain select straight_join count(*) from t1 as x1
  left join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;
 
set ndb_join_pushdown=off;
select straight_join count(*) from t1 as x1 
  left join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;
set ndb_join_pushdown=on;
select straight_join count(*) from t1 as x1 
  left join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.b = x1.b;

############
# However, When the scanchild itself is an outer join, we *can* push that scan operation
#
explain select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  left join t1 as x3 on x3.b = x1.b;
 
set ndb_join_pushdown=off;
select straight_join count(*) from t1 as x1 
  join t1 as x2 on x2.b = x1.a
  left join t1 as x3 on x3.b = x1.b;
set ndb_join_pushdown=on;
select straight_join count(*) from t1 as x1 
  join t1 as x2 on x2.b = x1.a
  left join t1 as x3 on x3.b = x1.b;

##############
# If we have a bushy lookup, with scandescendants depending on these lookups,
# the query is 'scan-bushy' through these lookups.
#
# Bushy execution is expected for these scans (x2 & x4) wrt. root (x1)
#
explain
select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.pk = x1.a join t1 as x4 on x4.b = x3.a;

set ndb_join_pushdown=off;
select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.pk = x1.a join t1 as x4 on x4.b = x3.a;
set ndb_join_pushdown=on;
select straight_join count(*) from t1 as x1
  join t1 as x2 on x2.b = x1.a
  join t1 as x3 on x3.pk = x1.a join t1 as x4 on x4.b = x3.a;

#############
# Test bushy lookups + 1scan, 
# (Regression test for previous commit: http://lists.mysql.com/commits/117571)
# Repeatable child rangescan with same parent should be allowed to be in 
# 'm_iterState != Iter_finished' if the child row didn't exist (outer join):

explain select straight_join count(*) from t1 as x1
  left join t1 as x3 on x3.b = x1.a
  join t1 as x2 on x2.pk = x1.a;
select straight_join count(*) from t1 as x1 
  left join t1 as x3 on x3.b = x1.a
  join t1 as x2 on x2.pk = x1.a;

# Modify rows to force null rows from outer join
update t1 set b=b+10;

select straight_join count(*) from t1 as x1 
  left join t1 as x3 on x3.b = x1.a
  join t1 as x2 on x2.pk = x1.a;

#Undo update
update t1 set b=b-10;

##############
# Testcase for: http://lists.mysql.com/commits/118917
# There used to be a bug in SPJ API resulthandling of incomplete
# child batches where we tested for incomplete fetch for any 
# childs (in a bushy scan) instead if this particular child batch
# being incomplete.
#
# In this testcase (x inner join y) will have incomplete
# childbatches, while (x left join z) will be complete. 

# Modify rows to force null rows from lookup(z) below
update t1 set u=u+100;

set ndb_join_pushdown=on;

--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

explain select straight_join count(*) from
  (t1 as x join t1 as y on y.b = x.a)
 left outer join t1 as z on z.u = x.a;
select straight_join count(*) from 
  (t1 as x join t1 as y on y.b = x.a)
 left outer join t1 as z on z.u = x.a;

--error 0,1193
set global debug=@save_debug;

#Undo update
update t1 set u=u-100;

#############
# Additional testcase added as part of WL introducing equi-join
# non-matching row elimination optimizations into the SPJ block
# Test query topology which lacked coverage. (Found to fail
# in manual or RQG testing)

# Modify rows to force null rows from outer joined lookup below
update t1 set a=a+pk;

set ndb_join_pushdown=on;
explain
select straight_join count(*) from t1 as x
  left join t1 as y on y.pk = x.a
  join t1 as z on z.b = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y on y.pk = x.a
  join t1 as z on z.b = x.b;

explain
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;

explain
select straight_join count(*) from t1 as x
  join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;

explain
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  join t1 as y2 on y2.pk = x.a
  join t1 as z on z.b = x.b;

explain
select straight_join count(*) from t1 as x
  left join (t1 as y join t1 as yy on yy.pk=y.u) on y.pk = x.a
  join t1 as z on z.b = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join (t1 as y join t1 as yy on yy.pk=y.u) on y.pk = x.a
  join t1 as z on z.b = x.b;

explain
select straight_join count(*) from t1 as x
  join t1 as z on z.b = x.b
  left join t1 as y on y.pk = x.a;
--sorted_result
select straight_join count(*) from t1 as x
  join t1 as z on z.b = x.b
  left join t1 as y on y.pk = x.a;

explain
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  left join t1 as y3 on y3.pk = x.a;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  left join t1 as y2 on y2.pk = x.a
  left join t1 as y3 on y3.pk = x.a;

explain
select straight_join count(*) from t1 as x
  left join t1 as y on y.pk = x.a
  left join t1 as z on z.pk = x.a
    left join t1 as y1 on y1.pk = y.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y on y.pk = x.a
  left join t1 as z on z.pk = x.a
    left join t1 as y1 on y1.pk = y.b;

explain
select straight_join count(*) from t1 as x
  join t1 as y on y.pk = x.a
    left join t1 as y1 on y1.pk = y.b
  left join t1 as z on z.pk = x.b;
--sorted_result
select straight_join count(*) from t1 as x
  join t1 as y on y.pk = x.a
    left join t1 as y1 on y1.pk = y.b
  left join t1 as z on z.pk = x.b;

explain
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  join t1 as y2 on y2.pk = x.b
    join t1 as z on z.b = y2.b;
--sorted_result
select straight_join count(*) from t1 as x
  left join t1 as y1 on y1.pk = x.a
  join t1 as y2 on y2.pk = x.b
    join t1 as z on z.b = y2.b;

#undo update
update t1 set a=a-pk;

##############

connection ddl;
drop index ix2 on t1;
create unique index ix2 on t1(a,u);

connection spj;
set ndb_join_pushdown=on;
explain
select straight_join * from
t1 as table1 join 
 (t1 as table2 join t1 as table3 on table3.a = table2.a)
 on table3.u = table1.u
 where table2.pk = 3;

--sorted_result
select straight_join * from
t1 as table1 join 
 (t1 as table2 join t1 as table3 on table3.a = table2.a)
 on table3.u = table1.u
 where table2.pk = 3;


##############
connection ddl;
drop table t1;

##############
# Test that branches of a bushy scan are correctly reset.

connection ddl;
CREATE TABLE t1 (
  a int NOT NULL,
  b int NOT NULL,
  c int NOT NULL,
  d int NOT NULL,
  PRIMARY KEY (`a`,`b`)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values (1,1,1,1), (1,2,1,1), (1,3,1,1), (1,4,1,2);

connection ddl;
CREATE TABLE t2 (
  a int NOT NULL,
  PRIMARY KEY (`a`)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE t3 (
  a int NOT NULL,
  b int NOT NULL,
  PRIMARY KEY (`a`,`b`)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection ddl;
insert into t2 values (0), (1), (2), (3), (4), (5), (6), (7), (8), (9);

connection spj;
# Make t3 so big that it takes multiple batches to scan it.
insert into t3 select 1, x1.a * 10+x2.a from t2 as x1 cross join t2 as x2;

--error 0,1193
set global debug='+d,max_64rows_in_spj_batches';

explain select straight_join count(*) from t1 as x0  
   join t3 as x1 on x1.a=x0.c
   join t1 as x2 on x2.a=x0.d
   join t3 as x3 on x3.a=x2.c
   join t1 as x4 on x4.a=x0.d and x4.b=x3.b;

select straight_join count(*) from t1 as x0  
   join t3 as x1 on x1.a=x0.c
   join t1 as x2 on x2.a=x0.d
   join t3 as x3 on x3.a=x2.c
   join t1 as x4 on x4.a=x0.d and x4.b=x3.b;

# If the first batch of an index scan has low parallelism and returns few rows,
# there is a mechanism that will try to query the remaining fragments within
# the same batch. This is done in order to avoid repeating other branches of 
# a bushy scan whenever possible. This is a test of that mechanism. Scan
# of x2 should return only one row. Therefore we should be able to fetch
# x2 in one batch and scan x3 only once.

let $scan_rows = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name='LOCAL_RANGE_SCANS_SENT', Value, 1);

--replace_column 10 # 11 #
explain select straight_join count(*) from t1 as x1  
   join t1 as x2 on x1.c=x2.a and x2.d=2
   join t3 as x3 on x1.d=x3.a;  

select straight_join count(*) from t1 as x1  
   join t1 as x2 on x1.c=x2.a and x2.d=2
   join t3 as x3 on x1.d=x3.a;

#####
# Bug #18175080 
# INCORRECT 'LOCAL_RANGE_SCAN' REPORTED FROM NDB_JOIN_PUSHDOWN_*.TEST
#
# Reported local_range_scan was not deterministic, so had
# to disable this subtest.
#
#--disable_query_log
#--eval select sum(val) - $scan_rows as Local_range_scans from ndbinfo.counters where block_name='DBSPJ' and counter_name='LOCAL_RANGE_SCANS_SENT';
#--enable_query_log

--error 0,1193
set global debug=@save_debug;

connection ddl;
drop table t1;
drop table t2;
drop table t3;

#############################################
# Test pruned index scan:
connection ddl;
create table t1(
       d int not null,
       e int     null,
       f int     null,
       a int not null,
       b int not null,
       c int not null,
       primary key (a,b,c))
engine = ndb partition by key (b) partitions 8;

connection spj;
insert into t1(a,b,c,d,e,f) values
 (1, 2, 3, 1, 2, 3),
 (1, 2, 4, 1, 2, 3),
 (2, 3, 4, 1, 2, 3),
 (3, 4, 5, 1, 2, 3),
 (4, 5, 6, 1, 2, 3),
 (5, 6, 7, 1, 2, 3),
 (6, 7, 8, 1, 2, 3),
 (7, 8, 9, 1, 2, 3);

# Find the total number of pruned range scans so far
let $pruned_range = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name='PRUNED_RANGE_SCANS_RECEIVED', Value, 1);

let $const_pruned_range = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name='CONST_PRUNED_RANGE_SCANS_RECEIVED', Value, 1);


set ndb_join_pushdown=on;

--replace_column 10 # 11 #
explain
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

connection ddl;
alter table t1 partition by key (a) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

connection ddl;
alter table t1 partition by key (a,b) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

connection ddl;
alter table t1 partition by key (b,a) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

#########
# const pruned testcase 
#########
connection ddl;
alter table t1 partition by key (b) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=2;

connection ddl;
alter table t1 partition by key (a) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=1 and y.b=x.e;
select straight_join * from t1 x, t1 y where y.a=0 and y.b=x.e;

# Non-const pruned as both partition keys are not const
connection ddl;
alter table t1 partition by key (a,b) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=1 and y.b=x.e;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=2;

##########
# Test pruned scan using an index:
# Declaring PK as 'using hash' will prevent that PK is used as index
# Declare PK / ix1 with mismatching column order will test correct
# usage of NdbRecord::distkey_indexes[]
##########
connection ddl;
alter table t1 drop primary key, add primary key using hash (d,b,a,c);
alter table t1 partition by key (b) partitions 8;
create index ix1 on t1(b,d,a);

connection spj;
--replace_column 10 # 11 #
explain
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

###########
# Partition keys may evaluate to null-values:
###########
insert into t1(a,b,c,d,e,f) values
 (8, 9, 0, 1,  null, 3),
 (9, 9, 0, 1,  2,    null);

connection ddl;
alter table t1 partition by key (b) partitions 8;

connection spj;
--sorted_result
select straight_join * from t1 x, t1 y where y.a=x.d and y.b=x.e;

# Verify pruned execution by comparing the NDB$INFO counters
--disable_query_log
--eval select sum(val) - $pruned_range as pruned from ndbinfo.counters where block_name='DBSPJ' and counter_name='PRUNED_RANGE_SCANS_RECEIVED'
--eval select sum(val) - $const_pruned_range as const_pruned from ndbinfo.counters where block_name='DBSPJ' and counter_name='CONST_PRUNED_RANGE_SCANS_RECEIVED'
--enable_query_log

connection ddl;
drop table t1;

###
# Sorted scan with sub scan used to not being pushable.
# However since v7.2.6(?) we support this by enforcing 
# batchRowSize=1 for the parent table in the scan-scan.
# (At the cost of more roundrtrips)
###
connection ddl;
create table t1 (pk int primary key, a int, b int) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create index ix1 on t1(b,a);

connection spj;
insert into t1 values (0,10,10);
insert into t1 values (1,10,20);
insert into t1 values (2,20,20);
insert into t1 values (3,10,10);
insert into t1 values (4,10,20);
insert into t1 values (5,10,20);
insert into t1 values (6,10,10);
insert into t1 values (7,10,10);
insert into t1 values (8,10,20);
insert into t1 values (9,10,10);


# This sorted scan-scan is pushed since V7.2.6
explain select x1.pk,x1.a,x1.b from t1 as x1
   join t1 as x2 on x1.a=x2.b 
   join t1 as x3 on x2.a=x3.b 
   order by x1.pk limit 70;
select x1.pk,x1.a,x1.b from t1 as x1 
   join t1 as x2 on x1.a=x2.b 
   join t1 as x3 on x2.a=x3.b 
   order by x1.pk limit 70;

# This query should not be pushed, since mysqld requires sorted
# results for the root scan.
explain select * from t1 as x1, t1 as x2 where x1.a=x2.b and x1.b = 3;
select * from t1 as x1, t1 as x2 where x1.a=x2.b and x1.b = 3;

connection ddl;
drop table t1;

########
# Test correct cleanup of MRR accesses being executed multiple times.
# This used to be bug#57481, and this is a SPJ specific testcase in addition to
# the specific testcase commited together with patch for this bug.
#######
connection ddl;
create table t (pk int primary key, a int) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
insert into t values 
  (1,1), (2,1),
  (4,3), (6,3),
  (7,4), (8,4);

connection spj;
--replace_column 10 # 11 #
explain
select distinct straight_join table1.pk FROM 
   t as table1  join
    (t as table2  join  
       (t as table3  join t as table4 on table3.pk = table4.a)
     on table2.pk =  table3.pk )
   on table1.a =  table4.pk
   where  table2.pk != 6;

--sorted_result
select distinct straight_join table1.pk FROM 
   t as table1  join
    (t as table2  join  
       (t as table3  join t as table4 on table3.pk = table4.a)
     on table2.pk =  table3.pk )
   on table1.a =  table4.pk
   where  table2.pk != 6;

connection ddl;
drop table t;

########
# SPJ variant of bug#57396
# Test correct format of an 'open bound'
########
connection ddl;
create table t (b int, a int, primary key (a,b)) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t values(0,0);

--replace_column 10 # 11 #
explain
select * from t as t1 join t as t2 on t2.a=t1.a where t1.a < 8 or t1.a >= 8;
select * from t as t1 join t as t2 on t2.a=t1.a where t1.a < 8 or t1.a >= 8;

connection ddl;
drop table t;

#######
# Testcase for bug introduced by initial fix for 
# bug#57601 'Optimizer is overly eager to request ordered access.'
# When we turned of 'sorted' for 'descending', we broke QUICK_SELECT_DESC
# which required result to be read as an ordered index access
# Note: Before V7.2.6, and as a result of WL5558, such 'turn of sorting'
# is not expected to happen any more.
#######
connection ddl;
create table t (pk1 int, pk2 int, primary key(pk1,pk2)) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t values (1,3), (3,6), (6,9), (9,1);

--replace_column 10 # 11 #
explain
select * from t as t1 join t as t2
  on t1.pk2 = t2.pk1 
  where t1.pk1 != 6
  order by t1.pk1 DESC;

select * from t as t1 join t as t2
  on t1.pk2 = t2.pk1 
  where t1.pk1 != 6
  order by t1.pk1 DESC;

connection ddl;
drop table t;

#######
# Testcase using 'REF_OR_NULL'
# 'ref_or_null' contains elements of left outer join wo/ being identical.
# 
connection ddl;
create table t (k int, uq int, unique key ix1 (uq)) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t values (1,3), (3,NULL), (6,9), (9,1);

# Currently we do not handle 'ref_or_null' correctly.
# It is therefore disabled as pushable
explain
select straight_join * from t as a join t as b 
  on a.uq=b.uq or b.uq is null;

--sorted_result
select straight_join * from t as a join t as b 
  on a.uq=b.uq or b.uq is null;

connection ddl;
drop table t;

########
# JT_SYSTEM testcase, 'a.k is null' is known 'false' ->
# Join condition will always fail, and all 'left joins' can be NULL complemented wo/
# even requiring to access left table (b) which becomes 'system' -> No pushed joins !
########
connection ddl;
create table t (k int primary key, uq int) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t values (1,3), (3,NULL), (6,9), (9,1);

--echo #############
--echo # WL#14370: AccessPath will contain a 'zero rows'-AccessPath in place
--echo #           of the known 'false' condition.
let $query =
select * from t as a left join t as b
  on a.k is null and a.uq=b.uq;

eval explain $query;
--replace_regex /  \(cost=.*//
eval explain format=tree $query;
--sorted_result
eval $query;

connection ddl;
drop table t;

#######
# Test of varchar query parameteres.
#######

connection ddl;
create table tc(
  a varchar(10) not null,
  b varchar(10),
  c varchar(10),
  primary key (a),
  unique key uk1 (b, c)
) engine=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into tc values ('aa','bb', 'x'), ('bb','cc', 'x'), ('cc', 'dd', 'x');

explain select * from tc as x1
  right outer join tc as x2 on x1.b=x2.a   
  left outer join tc as x3 on x2.b = x3.b and x1.c=x3.c;

--sorted_result
select * from tc as x1 
  right outer join tc as x2 on x1.b=x2.a   
  left outer join tc as x3 on x2.b = x3.b and x1.c=x3.c;

####
# Test that 'select ... for update' is not pushed, since this requires locking.
####

explain select * from tc as x1, tc as x2 where x1.b=x2.a for update;

explain select * from tc as x1, tc as x2 where x1.b=x2.a;

connection ddl;
drop table tc;

###
# prune with xfrm set incorrect keylen
#
connection ddl;
create table t1 (
  a varchar(16) not null,
  b int not null,
  c varchar(16) not null,
  d int not null,
  primary key (a,b)
) engine ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
  partition by key (a);

connection spj;
insert into t1  values ('aaa', 1, 'aaa', 1);
select * from t1 as q1, t1 as q2 where q1.a = 'aaa' and q1.c=q2.a;

connection ddl;
drop table t1;

########################
# Bug#17845161  'CORRUPT KEY IN TC, UNABLE TO XFRM'
# 
# Created an incorrect lookup key when a varchar()
# in the key was NULL

connection ddl;
CREATE TABLE t1 (
  id int NOT NULL AUTO_INCREMENT,
  t2_id int,
  PRIMARY KEY (id)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE t2 (
  id int NOT NULL AUTO_INCREMENT,
  t3_id varchar(20) DEFAULT NULL,
  PRIMARY KEY (id)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE t3 (
  id varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE t4 (
  pk int NOT NULL,
  id varchar(20) NOT NULL,
  PRIMARY KEY (pk),
  UNIQUE KEY (`id`)
) ENGINE=ndbcluster DEFAULT CHARSET=latin1
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";


connection spj;
INSERT INTO t1 VALUES (20, NULL);
INSERT INTO t1 VALUES (23, 24);

INSERT INTO t2 VALUES (24, NULL);

EXPLAIN
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t3 ON t3.id = t2.t3_id
 WHERE t1.id = 20;
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t3 ON t3.id = t2.t3_id
 WHERE t1.id = 20;


EXPLAIN
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t3 ON t3.id = t2.t3_id
 WHERE t1.id = 23;
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t3 ON t3.id = t2.t3_id
 WHERE t1.id = 23;

EXPLAIN
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t4 ON t4.id = t2.t3_id
 WHERE t1.id = 23;
SELECT *
  FROM t1
       INNER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t4 ON t4.id = t2.t3_id
 WHERE t1.id = 23;


EXPLAIN
SELECT *
  FROM t1
       LEFT OUTER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t2 as t3 ON t3.id = t1.t2_id;
--sorted_result
SELECT *
  FROM t1
       LEFT OUTER JOIN t2 ON t2.id = t1.t2_id
       LEFT OUTER JOIN t2 as t3 ON t3.id = t1.t2_id;

connection ddl;
DROP TABLE t1,t2,t3,t4;

#######################################
# Some tests for nested left joins.

connection ddl;
CREATE TABLE t1 (
  a int NOT NULL,
  b int NOT NULL,
  c int NOT NULL,
  d int,
  PRIMARY KEY (`a`,`b`),
  unique key(c)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values
(1,1,1,1), 
(1,2,2,1), 
(1,3,3,1), 
(1,4,4,1), 
(1,5,5,2), 
(1,6,6,2), 
(1,7,7,2), 
(1,8,8,2);

explain select count(*) from t1 as x1
   join (t1 as x2 
      left join (t1 as x3 
         cross join t1 as x4) 
      on x2.d=x3.a) 
   on x2.c is null or x1.a=x4.d;
select count(*) from t1 as x1 
   join (t1 as x2 
      left join (t1 as x3 
         cross join t1 as x4) 
      on x2.d=x3.a) 
   on x2.c is null or x1.a=x4.d;

explain select count(*) from t1 as x1
   left join (t1 as x2 
      cross join t1 as x3) 
   on x1.d=x2.a;
select count(*) from t1 as x1 
   left join (t1 as x2 
      cross join t1 as x3) 
   on x1.d=x2.a;

--echo #################
--echo # Prior to WL#14370 we did 'pending condition' analysis inside the
--echo # join pushdown handler. That code took a too conservative approach
--echo # in identifying such pending conditions, somethimes resulting in pushdown
--echo # to be rejected due to 'table condition can not be fully evaluated...'
--echo # The AccessPath construction code does a much better job of identifying
--echo # these pending condition, and placing them at the correct branch level.
--echo # As this information is now available to us through the AccessPath
--echo # integration, we eliminated our own (incomplete) code for doing such
--echo # analysis and could avoid such false rejections at the same time.
--echo #
--echo # Note the diff in the traditional and tree format explain below:
--echo # The traditional explain says table x4 is 'using where', which was
--echo # incorrectly identified as a trigger condition on join(x2,x4).
--echo # The tree format explain shows that it has been liftet out of that
--echo # join scope as a 'filter' on the entire x1..x4 join - Thus there is
--echo # noting preventing the left-join(x2,x4)
--echo #################

let $query =
select count(*) from t1 as x0
   left join (t1 as x1
      join (t1 as x2
         left join (t1 as x3
            join t1 as x4 on x3.d=x4.a)
         on x2.d=x3.a)
      on x2.c is null or x1.a=x4.d)
   on x0.d=x1.a;

eval explain $query;
--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;

connection ddl;
drop table t1;

## Test scan sorted on string field.
connection ddl;
create table t1 (pk char(10) primary key, u int not null) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
create table t2 (pk int primary key, u int not null) engine=ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values ('wh',1);
insert into t1 values ('ik',2);
insert into t1 values ('cu',3);
insert into t1 values ('pw',4);
insert into t1 values ('cq',4);

insert into t2 values (1,2), (2,3), (3,4), (4,5);

explain select * from t1 join t2 on t1.u = t2.pk order by t1.pk;
select * from t1 join t2 on t1.u = t2.pk order by t1.pk;

connection ddl;
drop table t1;
drop table t2;

########################################
# Test query with very long records.
connection ddl;
create table t1 (
  a char(10) primary key,
  b char(10) not null,
  c char(10) not null,
  l00 char(255) not null,
  l01 char(255) not null,
  l02 char(255) not null,
  l03 char(255) not null,
  l04 char(255) not null,
  l05 char(255) not null,
  l06 char(255) not null,
  l07 char(255) not null,
  l08 char(255) not null,
  l09 char(255) not null,
  l10 char(255) not null,
  l11 char(255) not null,
  l12 char(255) not null,
  l13 char(255) not null,
  l14 char(255) not null,
  l15 char(255) not null,
  l16 char(255) not null,
  l17 char(255) not null,
  l18 char(255) not null,
  l19 char(255) not null,
  l20 char(255) not null,
  l21 char(255) not null,
  l22 char(255) not null,
  l23 char(255) not null,
  l24 char(255) not null,
  l25 char(255) not null,
  l26 char(255) not null,
  l27 char(255) not null,
  l28 char(255) not null,
  l29 char(255) not null,
  l30 char(255) not null,
  l31 char(255) not null,
  index(c, b)
) engine=ndb character set latin1 partition by key(a) partitions 8;

connection spj;

insert into t1 values ('a','a','a','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x');

insert into t1 values ('b','b','b','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x');

insert into t1 values ('c','c','c','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x','x');

--replace_column 10 # 11 #
explain select count(*) from t1 as x1 join t1 as x2 on x1.b = x2.c;

select count(*) from t1 as x1 join t1 as x2 on x1.b = x2.c;

connection ddl;
drop table t1;

####################
# Test pruned child scans using parameter values (known regression).
####################
create table t1 
       (a int not null,
       b int not null, 
       c int not null,
       d int not null,
       primary key(a,b,c,d)) engine=ndb
       comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM"
       partition by key (b,c);

connection spj;
insert into t1 values (0x4f, 0x4f, 0x4f, 0x4f);

# Prune key depends on parent row.
--replace_column 10 # 11 #
explain select * from t1 as x1 
	join t1 as x2 on x1.c=0x4f and x2.a=0+x1.b and x2.b=x1.b 
	join t1 as x3 on x3.a=x2.d and x3.b=x1.d and x3.c=x2.c;

select * from t1 as x1 
	join t1 as x2 on x1.c=0x4f and x2.a=0+x1.b and x2.b=x1.b 
	join t1 as x3 on x3.a=x2.c and x3.b=x1.d and x3.c=x2.c;

# Prune key is fixed.
--replace_column 10 # 11 #
explain select * from t1 as x1 
	join t1 as x2 on x1.c=0x4f and x2.a=0+x1.b and x2.b=x1.b 
	join t1 as x3 on x3.a=x2.d and x3.b=x1.d and x3.c=0x4f;

select * from t1 as x1 
	join t1 as x2 on x1.c=0x4f and x2.a=0+x1.b and x2.b=x1.b 
	join t1 as x3 on x3.a=x2.c and x3.b=x1.d and x3.c=0x4f;

connection ddl;
drop table t1;

############################################################
# Bug#13990924 / Bug#64865 Large WHERE IN with SPJ leads to
#                          cluster shutdown
#
# Caused by incorrect error handling in SPJ block when
# there was a buffer overflow (>32K)
# (Pushed condition became to large)
#
# API also failed to prevent this from happen as it checked
# for size <= 64K, while actuall buffer size was 32K
# (Has now been increased)
############################################################
create table t1 (
  k1 int primary key,
  i int,
  name varchar(32),
  key (name)
)
default charset = utf8mb3
engine = ndb
comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

insert into t1 values (1, 1, 'Ole');
insert into t1 values (2, 2, 'Dole');
insert into t1 values (3, 3, 'Doffen');
insert into t1 values (4, 4, 'row# 999');

###################################################
# In the IN-value tests below we use regex filtering to
# avoid having the entire IN-value list in the result-file.
# We filter out all IN-values except the first 'foo' value
# and the last 'row# <last value', leaving the result:
#
#   in ('foo' .... 'row# <last value')
#
# Note, there is a regex bug:
#  Bug 86164 - std::regex crashes when matching long lines
#  https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86164
#
# The root cause is a too deep recursion when matching '+' and '*' patterns.
# in combination with a too long text to match. We hit that bug when
# regex-matching such long lines as generated in these IN-value lists.
#
# As a workaround for that bug we do the regex matching in two steps:
#
# 1) Consume all 'row# nnn' with a trailing ',' - Keeping just the last
#    row# nnn which has no trailing  ','
# 2) Add ' .... ' in front of the last remaining 'row#"
#
#######################################################

# These queries with large IN clauses exceeds the default memory limit of the
# range optimizer on 64 bit but not on 32 bit, thus cauing different result.
# Fix by setting a fairly low value in order to get consistent behaviour
set @save_range_opt_max = @@session.range_optimizer_max_mem_size;
set range_optimizer_max_mem_size = 64*1024;

echo ------------------------------------------------------------------;
echo;
# Build SPJ query with 2000 IN values
# This used to result in buffer overflow, but will now
# pass as buffer size is increased from 32K -> 64K
#
let $query = select * from t1 x, t1 y where y.k1=x.i and x.name in ('foo';
let $values = 0;
while ($values < 2000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query );

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;

echo ------------------------------------------------------------------;
echo;
# Same SPJ query with 4000 IN values
# This will hit the actuall limit of 64K and will be
# detected by API which will drop this pushed condition.
#   'Warning 4294 Scan filter is too large, discarded'
# (Pushed condition evaluated by ha_ndbcluster handler instead)
#
let $query = select * from t1 x, t1 y where y.k1=x.i and x.name in ('foo';
let $values = 0;
while ($values < 4000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query );

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;

echo ------------------------------------------------------------------;
echo;
# Build single table (non-SPJ) query with 4000 IN values
# Should give same 'Warning 4294' as above
let $query = select * from t1 x where x.name in ('foo';
let $values = 0;
while ($values < 4000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query );

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;


############################################################
# Bug #27397802 ENTIRE CLUSTER CRASHES WITH "MESSAGE TO BIG
#               IN SENDSIGNAL" WITH BIG IN CLAUSE.
#
# Similar problem as Bug#13990924; This time with a pushed
# condition as part of an EQ_REF child node
#
############################################################

insert into t1 values (5, 4, 'row# 1');
insert into t1 values (6, 4, 'row# 2');
insert into t1 values (7, 4, 'row# 3');
insert into t1 values (8, 4, 'row# 4');

echo ------------------------------------------------------------------;
echo;
# A 'small' 1000 valued IN-list is handled OK
#
let $query = select straight_join * from t1 x, t1 y where y.k1=x.i and y.name in ('foo';
let $values = 0;
while ($values < 1000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query ) order by x.k1;

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;

echo ------------------------------------------------------------------;
echo;
# Also a sufficient HUGE IN value list is ok as the pushed
# condition code is > 64K and catched by other 'Too large'
# checks.
#
let $query = select straight_join * from t1 x, t1 y where y.k1=x.i and y.name in ('foo';
let $values = 0;
while ($values < 4000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query ) order by x.k1;

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;


echo ------------------------------------------------------------------;
echo;
# A pushed condition with size between 32K - 64K was not 'Too large',
# but would require fragmented sending in order to work -> Crashed.
#
let $query = select straight_join * from t1 x, t1 y where y.k1=x.i and y.name in ('foo';
let $values = 0;
while ($values < 2000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query ) order by x.k1;

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;

set range_optimizer_max_mem_size = @save_range_opt_max;

drop table t1;

echo ------------------------------------------------------------------;
echo Bug#35185670 'mysqld crashes on expensive query';
echo       or we may assert, or just hang until timeout...;
echo;
#
# In a fragmenetd signal, the list of ReceiverId's were not correctly
# compiled into the REQuest. Some were duplicated, others were missing.
# In order to provoke the bug we need more than 16 receiverId's
#  -> Create table with many partitions.
#  -> Require the result to be ordered, which prevent multiple
#     fragments to be folded into the same receiver.
#
# Test case query is based on the above large IN-list queries.
#

create table t1 (
  k1 varchar(32) not null,
  k2 int not null default 0,
  primary key(k1,k2),
  i int default 0
) engine = ndbcluster
partition by key() partitions 32;

create table t2 (
  k1 int not null primary key
) engine = ndbcluster
partition by key() partitions 32;

let $query = insert into t1(k1) values ('foo');
let $values = 1;
while ($values < 2000)
{
  let $query = $query,('row# $values');
  inc $values;
}

###################
echo;
echo Inserting 2000 rows in table t1;

--disable_query_log
eval $query;
analyze table t1;

insert into t2(k1) values(0);
analyze table t2;
--enable_query_log

let $query = select * from t1 left join t2 on t2.k1=t1.i where t1.k1 in ('foo';
let $values = 0;
while ($values < 2000)
{
  let $query = $query,'row# $values';
  inc $values;
}
let $query = $query ) order by t1.k1, t1.k2;

echo;
echo Expect query and IN-condition to be pushed;
echo (If join_pushdown is enabled);

--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval explain $query;

--disable_result_log
--replace_regex /'row# [0-9]+',// /'row#/ .... 'row#/
eval $query;
--enable_result_log

drop table t1;
drop table t2;

############################################################
# Bug#14010406 LARGE PUSHED JOIN HIT ASSERT IN SPJ BLOCK
#
# Buffered rows (caused by PARENT refs) was prematurely
# released when there was no TN_ACTIVE treeNodes childs.
# However, in bushy scans, a scan branch can be 'repeated'
# even if its previous execution was 'complete'. 
#
# Thus we have to use a less eager release strategy where
# we don't release any buffered rows until we prepare for
# a NEXTREQ which will fetch more rows into the treeNode.
############################################################

create table t(
  pk int primary key auto_increment,
  i int, 
  j int,
  k int,
  index(i,j),
  index(i),
  index(j),
  index(k)
) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

insert into t(i,j,k) values
   (1,1,1), (1,1,1), (1,1,1),
   (2,2,2), (2,2,2), (2,2,2);

--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

--replace_column 10 # 11 #
explain
select straight_join count(*) from 
  t as t1
  join t as t2 on t2.i = t1.i
  join (t as t3 join t as t4 on t4.k=t3.k join t as t5 on t5.i=t4.i and t5.j=t3.j) on t3.pk=t1.j
  join t as t6 on t6.k = t1.k
  where t1.i < 2;

select straight_join count(*) from 
  t as t1
  join t as t2 on t2.i = t1.i
  join (t as t3 join t as t4 on t4.k=t3.k join t as t5 on t5.i=t4.i and t5.j=t3.j) on t3.pk=t1.j
  join t as t6 on t6.k = t1.k
  where t1.i < 2;

--error 0,1193
set global debug=@save_debug;

drop table t;

####################################################
# Test LQH handling of zero-length key in LQHKEYREQ
# Bug#
create table t1 (a int primary key, b int, c int, index(b,c)) engine = ndb
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";
insert into t1 values (4,null, 2);

explain
select x.a from t1 as x join t1 as y on y.a = x.b where x.a=4;
select x.a from t1 as x join t1 as y on y.a = x.b where x.a=4;

drop table t1; 

####################################################
# Regression test for Bug#14644936 "INEFFICIENT AND INCORRECT EXECUTION OF 
# PUSHABLE OUTER JOINS".
####################################################

connection ddl;
CREATE TABLE t1 (
  a int NOT NULL,
  b int DEFAULT NULL,
  c int NOT NULL,
  d int NOT NULL,
  PRIMARY KEY (`a`)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

create unique index ix1 on t1(b,c) using hash;

connection spj;

insert into t1 values (1,NULL,1,1);


explain select * from t1 as x1 left join (t1 as x2 join t1 as x3 on x2.d=x3.c) on x1.b=x3.b;

# Record value before query.
create temporary table scan_count
       select * from performance_schema.global_status 
       where variable_name = 'Ndb_scan_count';

# Query gives wrong result on mysql-trunk-cluster, and extra scan on both
# mysql-5.5-cluster-7.2 and mysql-trunk-cluster.
select * from t1 as x1 left join (t1 as x2 join t1 as x3 on x2.d=x3.c) on x1.b=x3.b; 

# Bug causes value to increase by 3 rather than 2.
select scan_count.VARIABLE_NAME,
       old.VARIABLE_VALUE - scan_count.VARIABLE_VALUE  
       from scan_count, performance_schema.global_status as old 
       where old.variable_name = 'Ndb_scan_count';

drop table scan_count;

connection ddl;
drop table t1;

##############
# Bug#16925513: HIT DBUG_ASSERT IN SPJ BLOCK, ~LINE 4406
#
# Testcase extracted from failing RQG test.

connection ddl;
CREATE TABLE table1 (
  col_int_unique int(11), 
  PRIMARY KEY (col_int_unique)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE table3 (
  col_int int(11) NOT NULL DEFAULT '0',
  KEY (col_int)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE table4 (
  col_int int(11) DEFAULT NULL,
  pk int(11) NOT NULL,
  PRIMARY KEY (pk)
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE table6 (
  col_int int(11) DEFAULT NULL,
  col_int_unique int(11) DEFAULT NULL
) ENGINE=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into table6 values
 (2,NULL), 
 (2,NULL), 
 (2,NULL), 
 (2,NULL), 
 (2,NULL), 
 (2,NULL), 
 (2,NULL), 
 (2,NULL);

--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

EXPLAIN
 SELECT * FROM
 table1 RIGHT JOIN 
   table3 LEFT JOIN table4 ON table3.col_int = table4.col_int 
     JOIN
   table6 ON table4.pk = table6.col_int_unique 
 ON table1.col_int_unique = table6.col_int;

--sorted_result
 SELECT * FROM
 table1 RIGHT JOIN 
   table3 LEFT JOIN table4 ON table3.col_int = table4.col_int 
     JOIN
   table6 ON table4.pk = table6.col_int_unique 
 ON table1.col_int_unique = table6.col_int;


--error 0,1193
set global debug=@save_debug;

connection ddl;
drop table table6;
drop table table4;
drop table table3;
drop table table1;


--echo 5.6 tests
#######################################
# MySQL 5.6 include improved optimizer
# handling of subqueries. Some specific
# test for handling limitations / problems
# specific to these features

#############################################
# Testing of subqueries and join pushdown
#
#  Note that subqueries has limitations very similar
#  to outer joins. 
#############################################

##############
# Bug #16664035
# PUSHED JOIN TOGETHER WITH 'FIRSTMATCH' STRATEGY MAY RETURN TOO MANY ROWS

connection ddl;
create table t1 (
  a int not null,
  b int not null,
  c int not null,
  d int not null,
  primary key (`a`,`b`),
  key(c), key(d)
) engine=ndbcluster
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

connection spj;
insert into t1 values
(1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4),
(1,2,5,1), (1,3,1,2), (1,4,2,3),
(2,1,3,4), (2,3,4,5), (2,4,5,1),
(3,1,1,2), (3,2,2,3), (3,4,3,4),
(4,1,4,5), (4,2,5,1), (4,3,1,2);

# Use debug hook to enforce only 4 rows in each batch (Two roundtips)
--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

# Make use of FirstMatch more likely:
set @save_optimizer_switch = @@optimizer_switch;
set optimizer_switch='materialization=off';

# 'subq' should use 'ref, FirstMatch(t1)', preventing join pushdown
explain
select count(*) from t1 where 
  t1.c in (select c from t1 as subq);
select count(*) from t1 where
  t1.c in (select c from t1 as subq);

explain
select count(*) from t1 where 
  t1.c in (select c from t1 as subq1) and
  t1.d in (select d from t1 as subq2);
select count(*) from t1 where 
  t1.c in (select c from t1 as subq1) and
  t1.d in (select d from t1 as subq2);

explain
select count(*) from t1 where 
  t1.c in (select c from t1 as subq1 where 
    subq1.c in (select c from t1 as subq2));
select count(*) from t1 where 
  t1.c in (select c from t1 as subq1 where 
    subq1.c in (select c from t1 as subq2));

explain
select count(*) from t1 where 
  t1.c in (select subq1.c from t1 as subq1 straight_join t1 as subq2 on subq1.a = subq2.c);
select count(*) from t1 where 
  t1.c in (select subq1.c from t1 as subq1 straight_join t1 as subq2 on subq1.a = subq2.c);

set optimizer_switch=@save_optimizer_switch;

--error 0,1193
set global debug=@save_debug;

####################################
--echo #
--echo # Bug#29860378
--echo #   RESULTS NOT SORTED AS SPECIFIED WHEN QUERY IS A 'PUSHED JOIN'
--echo #

# Force a small batch size in order to reproduce bug without needing
# a large test table.
--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

explain
select straight_join t1.* from
  t1 join t1 as t2 on t2.d = t1.a
  where t1.a > 0
  order by t1.a,t1.b;

select straight_join t1.* from
  t1 join t1 as t2 on t2.d = t1.a
  where t1.a > 0
  order by t1.a,t1.b;

explain
select straight_join t1.a,t1.b,count(*) from
  t1 join t1 as t2 on t2.d = t1.a
  where t1.a > 0
  group by t1.a,t1.b;

--sorted_result
select straight_join t1.a,t1.b,count(*) from
  t1 join t1 as t2 on t2.d = t1.a
  where t1.a > 0
  group by t1.a,t1.b;

--error 0,1193
set global debug=@save_debug;


##################################################
# Bug##26926666
#   'LOOSESCAN' TABLES SHOULD NOT BE CHILD MEMBERS IN A PUSHED JOIN
#
##################################################

######
# Expect a query plan where the subquery table1s becomes
# a child candidate in a pushed join. 'LooseScan' require
# sorted results to be returned from the (child) table, which
# we do not implement.

connection spj;
set @save_optimizer_switch = @@optimizer_switch;
set @@optimizer_switch='semijoin=on';
set @@optimizer_switch='loosescan=on';

explain SELECT count(*)
  FROM (t1 AS table1 JOIN t1 AS table2 USING(a,b))
  WHERE table1.b IN
    (SELECT /*+ SEMIJOIN(LOOSESCAN)*/ table1s.c FROM t1 as table1s);
SELECT count(*)
  FROM (t1 AS table1 JOIN t1 AS table2 USING(a,b))
  WHERE table1.b IN
    (SELECT /*+ SEMIJOIN(LOOSESCAN)*/ table1s.c FROM t1 as table1s);

########
# Same query with 'FirstMatch', suplements FirstMatch (bug#16664035)
# testcase above

set @@optimizer_switch='firstmatch=on';

explain SELECT count(*)
  FROM (t1 AS table1 JOIN t1 AS table2 USING(a,b))
  WHERE table1.b IN
    (SELECT /*+ SEMIJOIN(FIRSTMATCH)*/ table1s.c FROM t1 as table1s);
SELECT count(*)
  FROM (t1 AS table1 JOIN t1 AS table2 USING(a,b))
  WHERE table1.b IN
    (SELECT /*+ SEMIJOIN(FIRSTMATCH)*/ table1s.c FROM t1 as table1s);

set optimizer_switch=@save_optimizer_switch;

##################################################
# Bug#26919289:
#    mysqld crash during join_pushdown analysis
#
# The mysql optimizer introduce syntetic JOIN_TAB
# elements representing where the materialized subq
# should be accessed in the query plan. As these
# are not representing 'real tables', their 'tableno'
# was not set up in ndb_pushed_builder_ctx C'tor.
# It effectively contained uninitialized data, which was
# then later used to access a 'tableno-bitmask'.
###################################################

--echo ####################################################################
--echo # WL#14370: Change EXPLAIN to use 'format=tree'. Traditional explain
--echo # didn't correctly represent the order of tables in MATERIALIZED
--echo # sub queries. That resulted in some confusing 'EXPLAIN_NO_PUSH' diffs
--echo # where the reported root/child order didn't make sense.
--echo # As the tree-format explain will show, the changed output
--echo # make more sense related to the query plan represented by the
--echo # AccessPath tree.
--echo # WL#14370: Materialized semijoin's is not the only SJ-strategi
--echo # where we do no pushdown across main-query -> sub-query border.
--echo # (The sub-query itself may be pushed though)
--echo ###################################################################

connection spj;
set @save_optimizer_switch = @@optimizer_switch;
set @@optimizer_switch='semijoin=on';
set @@optimizer_switch='materialization=on';

let $query =
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t1.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ c from t1 as t3);

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;


let $query =
select count(*)
from t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
where t1.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ c from t1 as t3);

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;


let $query =
select count(*)
from (select * from t1 where t1.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ c from t1 as t3)) as t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;


let $query =
select count(*)
from (select * from t1 where t1.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ c from t1 as t3)) as t1
join t1 as t2 on t2.a = t1.b and t2.b = t1.c
where t1.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ c from t1 as t4);

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;


set optimizer_switch='block_nested_loop=off';

let $query =
select count(*)
from t1 cross join t1 as t2
where t2.c IN (select /*+ SEMIJOIN(MATERIALIZATION)*/ t4s.c
  from t1 as t3s join t1 as t4s on t4s.a = t3s.b);

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;

set optimizer_switch=@save_optimizer_switch;


###################################################
# Bug #26984919
#   SPJ: 'DUPLICATE WEEDOUT' STRATEGY MAY RETURN INCORRECT RESULTS

###################################################

# Use debug hook to enforce only 4 rows in each batch (multiple roundtips)
--error 0,1193
set global debug='+d,max_4rows_in_spj_batches';

connection spj;
set @save_optimizer_switch = @@optimizer_switch;
set @@optimizer_switch='semijoin=on';

explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t1.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t3s.c from t1 as t3s
  join t1 as t4s on t4s.a = t3s.b);

select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t1.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t3s.c from t1 as t3s
  join t1 as t4s on t4s.a = t3s.b);


explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t2.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t3s.c from t1 as t3s
  join t1 as t4s on t4s.a = t3s.b);

select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t2.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t3s.c from t1 as t3s
  join t1 as t4s on t4s.a = t3s.b);


explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t1.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);

select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t1.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);


explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t2.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);

select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t2.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);


explain
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t3.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);

select count(*)
from t1
join t1 as t2 on t2.a = t1.b
join t1 as t3 on t3.a = t2.b
where t3.c IN (
  select /*+ SEMIJOIN(DUPSWEEDOUT)*/ t4s.c from t1 as t4s
  join t1 as t5s on t5s.a = t4s.b
  join t1 as t6s on t6s.a = t5s.b
);


--error 0,1193
set global debug=@save_debug;

set optimizer_switch=@save_optimizer_switch;

###################################################
# Bug#27022925
#   SPJ: 'MATERIALIZED' SEMI JOINS ARE NOT CONSIDDERED FOR JOIN PUSHOWN
#
#   Joins entirely inside a 'MATERIALIZED' semi join
#   not considdered for join pushdown.
#
# Test cases should demonstrate that the 't3s join t4s'
# subqueries can now be pushed down, and materialized.
#
###################################################

--echo ###########
--echo # WL#14370: EXPLAIN need to use 'format=tree as table access order
--echo # in MATERIALIZED execution is not currectly represented by
--echo # the traditional explain.
--echo ###########

let $query =
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t1.c IN (
  select /*+ SEMIJOIN(MATERIALIZATION)*/ t3s.c from t1 as t3s
  join t1 as t4s on t4s.a = t3s.b);

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;


let $query =
select count(*)
from t1
join t1 as t2 on t2.a = t1.b
where t1.c IN(
  select /*+ SEMIJOIN(MATERIALIZATION)*/ t3s1.c from t1 as t3s1
  join t1 as t4s1 on t4s1.a = t3s1.b
 )
and t1.d IN (
  select /*+ SEMIJOIN(MATERIALIZATION)*/ t3s2.c from t1 as t3s2
  join t1 as t4s2 on t4s2.a = t3s2.b
 );

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
eval $query;

#############################################
# Subqueries-end
#############################################


###################################################
# Bug#33416308
#    Incorrect result for pushed join in combination with batched_key_access
#
# SPJ API / handler integration didn't implement retrieval of the
# RANGE_NO pseudo column. Thus, when MRR specified multiple Bound's,
# and that MRR operation was the root of a pushed join, we failed
# to related the returned SPJ rows with the correct 'Batched Key'
#
##################################################

# We use optimizer hints to ensure:
#  - t2 is BKA joined (using MRR) with t1.
#  - t3 is _not_ BKA joined with t2, thus enabling
#      t2 join t3 to be pushed.
#
# 't1 BKA_JOIN t2' will use MRR access for the
# pushed join root t2, which will need RANGE_NO's from t2 results
# in order to relate them to the correct batched t1 row.
#
explain
select /*+ BKA(t2) NO_BKA(t3) */ t1.a, t2.a, t3.a
from t1
  straight_join t1 as t2 on t2.a = t1.c
  straight_join t1 as t3 on t3.a = t2.c and t3.b=t2.d;
--sorted_result
select /*+ BKA(t2) NO_BKA(t3) */ t1.a, t2.a, t3.a
from t1
  straight_join t1 as t2 on t2.a = t1.c
  straight_join t1 as t3 on t3.a = t2.c and t3.b=t2.d;

# Variant where t3 join condition refers t1.
# That will hit an assert(key_cmp... added as part of patch
explain
select /*+ BKA(t2) NO_BKA(t3) */ t1.a, t2.a, t3.a
from t1
  straight_join t1 as t2 on t2.a = t1.c
  straight_join t1 as t3 on t3.a = t1.c and t3.b=t2.d;
--sorted_result
select /*+ BKA(t2) NO_BKA(t3) */ t1.a, t2.a, t3.a
from t1
  straight_join t1 as t2 on t2.a = t1.c
  straight_join t1 as t3 on t3.a = t1.c and t3.b=t2.d;

connection ddl;
drop table t1;

##############
# 16999886 ORDER BY DOESN'T WORK WITH JOIN
# (Limited to pushed join + DESC order only)

connection ddl;
CREATE TABLE ndb_order_test (
  node_id int(10) unsigned NOT NULL,
  user_id int(10) unsigned NOT NULL,
  sort_number int(10) unsigned NOT NULL,
  KEY node_id (node_id,sort_number)
) ENGINE=ndbcluster DEFAULT CHARSET=utf8mb3
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";

CREATE TABLE ndb_user_test (
  user_id int(10) unsigned NOT NULL AUTO_INCREMENT,
  name varchar(20) NOT NULL,
  PRIMARY KEY (user_id)
) ENGINE=ndbcluster DEFAULT CHARSET=utf8mb3 AUTO_INCREMENT=2
  comment="NDB_TABLE=PARTITION_BALANCE=FOR_RP_BY_LDM";


connection spj;
INSERT INTO ndb_order_test (node_id, user_id, sort_number) VALUES
(68, 1, 1398029),
(68, 1, 549053);

INSERT INTO ndb_user_test (user_id, name) VALUES
(1, 'Shawn');


EXPLAIN 
SELECT *
 FROM ndb_order_test JOIN ndb_user_test USING (user_id)
 WHERE node_id = 68
 ORDER BY sort_number DESC;

SELECT *
 FROM ndb_order_test JOIN ndb_user_test USING (user_id)
 WHERE node_id = 68
 ORDER BY sort_number DESC;

EXPLAIN 
SELECT *
 FROM ndb_order_test JOIN ndb_user_test USING (user_id)
 WHERE node_id = 68
 ORDER BY sort_number ASC;

SELECT *
 FROM ndb_order_test JOIN ndb_user_test USING (user_id)
 WHERE node_id = 68
 ORDER BY sort_number ASC;

connection ddl;
DROP TABLE ndb_order_test, ndb_user_test;


--echo ##################
--echo #
--echo # Bug #29501263 CRASH IN SPJ BLOCK, ILLEGAL ACCESS
--echo #               TO ARRAYPOOL<T>::GETPTR
--echo #
--echo ##################

create table t1 (
  pk int primary key,
  i1 int
) engine = ndb;

insert into t1 values (1,1),(2,2),(3,3);

alter table t1 add column (i2 int, i3 int, i4 int, i5 int);
update t1 set i2=i1, i3=i1, i4=i1, i5=i1;

alter table t1 add index ix1(i1);
alter table t1 add index ix2(i2);
alter table t1 add index ix3(i3);
alter table t1 add index ix4(i4);
alter table t1 add index ix5(i5);
alter table t1 add unique index uix(i4,i5);

--sorted_result
select straight_join * from
  t1
    join t1 as t2 on t2.i1 = t1.i1
      join t1 as t3 on t3.pk = t2.i2
        left join t1 as t4 on t4.pk = t3.i3
        left join t1 as t5 on t5.i4 = t2.i4 and t5.i5 = t1.i5;

drop table t1;


--echo ##################
--echo #
--echo # Bug#32203548 REQUIRE_FAILED WHEN COMPARE_NDBRECORD()
--echo #                SORT-MERGE SPJ RESULTS FROM INDEX
--echo #
--echo ##################

create table t1 (
  a int not null,
  b int not null,
  c varchar(1) not null,
  d varchar(1) not null,
  primary key (a,b),
  index ix2 (d,c)
) engine=ndbcluster;

# Note that we insert all "1" into column d, such that
# the merge sort on index 'ix2 (d,c)' will always find
# column 'd' equal, and continue comparing column 'c'
# if we do not break out of compare loop for columns not
# selected.
#
insert into t1 values
(1,1,"1","1"), (2,2,"2","1"), (3,3,"3","1"), (4,4,"4","1"),
(1,2,"5","1"), (1,3,"1","1"), (1,4,"2","1"),
(2,1,"3","1"), (2,3,"4","1"), (2,4,"5","1");

# We force index 'ix2' to be used for 'order by'
explain
select t1.d from t1 FORCE INDEX FOR ORDER BY (ix2)
straight_join t1 as t2 on t2.a = t1.a
  order by t1.d;

select t1.d from t1 FORCE INDEX FOR ORDER BY (ix2)
straight_join t1 as t2 on t2.a = t1.a
  order by t1.d;

drop table t1;

--echo ##################
--echo #
--echo # Specific WL-14370, 'AccessPath' tests
--echo # (Unknown if/how this worked pre-wl-14370)
--echo #
--echo ##################

--echo Testcase for AccessPath::NESTED_LOOP_SEMIJOIN_WITH_DUPLICATE_REMOVAL
--echo Expect explain: 'Nested loop semijoin with duplicate removal on...'
--echo   (Hardly ever used unless forced to...)


--echo Testcase for AccessPath::WINDOWING
# (Picked from main.subquery_scalar_to_derived_correlation.test)

create table t2(a int) engine=ndbcluster;
insert into t2 values(1), (2);
create table t3(a int, b int) engine=ndbcluster;
insert into t3 values(1, 3), (2, 3);

# Below query is no longer valid, but kept for reference.
let $query =
  select a,
       (select sum(a) over w from t2 window w as(order by t3.a) limit 1)
  from t3;

--error ER_INVALID_OUTER_REFERENCE
eval explain format=tree $query;
--sorted_result
--error ER_INVALID_OUTER_REFERENCE
eval $query;

# Below query is added to have a query with similar plan to what above query
# had before it got invalid.
let $query =
  select a,
       (select sum(a) over w from t2 window w as(order by "whatever") limit 1)
  from t3;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
--sorted_result
eval $query;

drop table t2,t3;

#WL#14370: Query_expression with multiple Query_blocks:
# (Testing Accesspath::APPEND of multiple STREAMs.)
# The constructed AQP::Join_plan is limited to handling single
# Query_blocks, which is implemented by just iterating over the
# 'block' in the Query_expression. Thus we dont have to handle
# Accesspath::APPEND and multiple 'blocks' in the 'plan'.
#

create table t1 (
  a int not null,
  b int not null,
  c int not null,
  d int not null,
  primary key (`a`,`b`)
) engine=ndbcluster
partition by key() partitions 8;

insert into t1 values
(1,1,1,1), (2,2,2,2), (3,3,3,3), (4,4,4,4),
(1,2,5,1), (1,3,1,2), (1,4,2,3),
(2,1,3,4), (2,3,4,5), (2,4,5,1),
(3,1,1,2), (3,2,2,3), (3,4,3,4),
(4,1,4,5), (4,2,5,1), (4,3,1,2);

let $query =
  select *
  from t1
    straight_join t1 as t2 on t2.a = t1.b+0 and t2.b = t1.c
    straight_join t1 as t3 on t3.a = t1.b and t3.b = t2.b
  where t1.a=1 and t1.d=1;

--replace_regex /  \(cost=.*//
eval explain format=tree $query union all $query;
--sorted_result
eval $query union all $query;

--replace_regex /  \(cost=.*//
eval explain format=tree $query union $query;
--sorted_result
eval $query union $query;

drop table t1;

--echo ##################
--echo #
--echo # Bug#33669039 Stale rows returned from SPJ API,
--echo #              hit assert(key_cmp_if_same(...)) in debug build
--echo #
--echo ##################

create table t (
pk int primary key,
a int,
b int,
c int,
d int
) engine = ndbcluster;


##############################
# The inserted rows, in combination with query,
# will do a self-join between all rows, except
# the row where pk=7, containing a=-1
insert into t values (0,0,0,0,0);
insert into t values (1,1,1,1,1);
insert into t values (2,2,2,2,2);
insert into t values (3,3,3,3,3);
insert into t values (4,4,4,4,4);
insert into t values (5,5,5,5,5);
insert into t values (6,6,6,6,6);
insert into t values (7,-1,7,7,7);
insert into t values (8,8,8,8,8);
insert into t values (9,9,9,9,9);
insert into t values (10,10,10,10,10);
insert into t values (11,11,11,11,11);
insert into t values (12,12,12,12,12);
insert into t values (13,13,13,13,13);
insert into t values (14,14,14,14,14);
insert into t values (15,15,15,15,15);


##############################
# The query below has the join nests t1 oj (t2,t3) oj (t4,t5). In addition
# There are join condition dependencies between the (t4,t5) nests, and t3
# in the other outer-nest.
# When the iterator executor evaluate the join for the row with pk=7 it
# will not find any t2 rows where t2.pk = t1.a. This will also conclude
# with a 'non match' for the nest (t2,t3)... *without* a new t3 row needed
# to be read.
# The iterator executor will then continue with trying to find matches
# for the (t4,t5) nest. This nest will have join dependencies on t3, which
# now has an old (invalid) 'current row' as read from t3 was skipped in the
# previous step.
#
let $query=
select t1.pk, t2.pk, t3.pk, t4.pk, t5.pk
from t as t1
  left join (
    t as t2
      straight_join t as t3 on t3.pk = t2.b
  ) on t2.pk = t1.a
  left join (
    t as t4
      straight_join t as t5
  ) on t4.pk = t1.c and t5.pk = t3.d;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
--sorted_result
eval $query;

drop table t;


--echo ##################
--echo #
--echo # Bug#34482783 NDB: mysqld crash in ::is_pushable_within_nest()
--echo #
--echo ##################

create table t (
  pk int primary key,
  col_int_key int not null,
  col_int int not null,
  key(col_int_key)
) engine = ndbcluster;

# No rows needed in table to provoke bug

let $query=
SELECT *
FROM t AS table1
  LEFT JOIN t AS table2
    JOIN t AS table3 ON table2.col_int IS NULL  # <- 'zero rows'
  ON table1.col_int = table2.col_int AND
     table1.col_int_key = table2.col_int_key AND
     table1.pk = table3.pk;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;
--sorted_result
eval $query;

drop table t;


--echo ##################
--echo #
--echo # Bug#34723413 A 'pushed join' should not start with a scan-table
--echo #              returning very few rows .
--echo #
--echo ##################

create table t10 (
  k int not null auto_increment,
  i int,
  primary key(k),
  key(i)
) engine = ndbcluster;

insert into t10(i) values (1),(2),(3),(4),(5),(6),(7),(8),(9),(0);

create table t100 like t10;
insert into t100(i)
 select x.i from t10 as x, t10 as y;

create table t1000 like t10;
insert into t1000(i)
 select x.i from t10 as x, t10 as y, t10 as z;

# Make t10 even smaller, increase join-fanout on 'i' for t100 and t1000
delete from t10 where i > 2;
update t100 set i = i/3;
update t1000 set i = i/3;

analyze table t10,t100,t1000;

############################
# We could have pushed 't10 join t1000 join t100'
# However the small table t10 might not deliver rows to all SPJ workers,
# leaving some of them idle. Thus it will usually be better to :
# - Fetch t10 rows
# - For every t10 row: Push 't1000 join t100'
#
# Expect the explain-warning:
#
# Didn't push table 't10' as root, too few rows to enable full parallelism
#
--replace_regex /  \(cost=.*//
explain format=tree
select *
from t10
  straight_join t1000 on t1000.i = t10.i
  straight_join t100 on t100.k = t1000.k;

############################
# However:
# Table 't100' is an ancestor of t10, and can't be made
# and t1000 ancestor. Not pushing t10 will yield t1000 and t100
# unpushed as well -> Push all 3 tables as first planned.
#
--replace_regex /  \(cost=.*//
explain format=tree select *
from t10
  straight_join t1000 on t1000.i = t10.i
  straight_join t100 on t100.k = t10.k;

drop table t10,t100,t1000;


--echo ##################
--echo #
--echo # Bug#34782276:
--echo #   Improve SPJ-internal execution plan, evaluate inner-joins first
--echo #
--echo ##################
#
# The SPJ block will build its own query plan where it will evaluate
# inner-joins first. Even in a star-join plan the joins will be evaluated
# in sequence and found matches noted in the common ancestor. Later joins
# will be skipped if some of the previously evaluated joins didn't find
# a match. (It is a property of the inner-join that matches are required
# for all tables in the same inner join 'nest').
# This will reduce the work needed to be performed by the data nodes
# in later table REQuests.
#
# Test case is the query tree:       t1
#                                   /   \
#                                  t2   t3
#
# There are matches for all rows in the join(t1,t3). However only 3 of the 9
# rows will match in join(t1,t2). The SPJ block will create its own execution
# Plan where:
#   1) join(t1,t2), Annotate t1 rows where matches are found.
#   2) Generate t3 requests from buffered t1 rows having matches.
# -> There should only be 3 keys in the REQuest sent to t3

create table t (
  k int,
  a int,
  key ix1(k),
  key ix2(a)
) engine = ndb;

insert into t values
  (0,0), (1,1), (2,2),
  (3,0), (4,1), (5,2),
  (6,0), (7,1), (8,2);

let $old_val = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name = 'SCAN_ROWS_RETURNED', Value, 1);

# This test case is just for reference - Worked as expected even before bug fix.
let $query=
select straight_join *
from t as t1
  inner join t as t2 on t2.a = t1.k
  inner join t as t3 on t3.k = t1.k;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;

let $old_val = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name = 'SCAN_ROWS_RETURNED', Value, 1);

--disable_result_log
eval $query;
--enable_result_log

--echo ############
--echo # Verify the expect 21 rows were returned from SPJ:
--echo # - 2 x 9 rows from t1 inner join t2
--echo # - 3 rows from t1 join t3
--echo # -> 21 rows (0 *SPJ* rows when not join-pushed (BKA))
--echo #
--disable_query_log
--eval select sum(val) - $old_val as SPJ_rows_returned from ndbinfo.counters where block_name="DBSPJ" and counter_name = "SCAN_ROWS_RETURNED"
--enable_query_log


##### Same test case with outer join:
#
# Should stil evaluate t1 join t2 first.
# A non-match on t2 will eliminate the inner joined t1 rows.
# Thus, t1 left join t3 may be skipped for t1 rows not having t2 matches
#
let $query=
select straight_join *
from t as t1
  inner join t as t2 on t2.a = t1.k
  left join t as t3 on t3.k = t1.k;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;

let $old_val = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name = 'SCAN_ROWS_RETURNED', Value, 1);

--disable_result_log
eval $query;
--enable_result_log

--echo ############
--echo # As above, t1 inner join t2 is evaluated first
--echo # - 2 x 9 rows from join(t1,t2)
--echo # - Only the 3 matching t1 rows are requested from t3!
--echo # -> still 21 rows (and still 0 *SPJ* rows when not join-pushed (BKA))
--echo #
--disable_query_log
--eval select sum(val) - $old_val as SPJ_rows_returned from ndbinfo.counters where block_name="DBSPJ" and counter_name = "SCAN_ROWS_RETURNED";
--enable_query_log


##### Same test case with outer join evaluated before inner join:
#
# There is a legacy limitation in the SPJ API protocol, where scans need
# to be evaluated in the same order as specified in the optimizer table order.
# Test case verify that we do *not* skip t3 rows in these cases.
# (As t1 left join t2 will not eliminate non matching t1 rows and we cant evaluate
#  t1 inner join t3 first due to legacy limitation.)
#
let $query=
select straight_join *
from t as t1
  left join t as t2 on t2.a = t1.k
  inner join t as t3 on t3.k = t1.k;

--replace_regex /  \(cost=.*//
eval explain format=tree $query;

let $old_val = query_get_value(select sum(val) as Value from ndbinfo.counters where block_name='DBSPJ' and counter_name = 'SCAN_ROWS_RETURNED', Value, 1);

--disable_result_log
eval $query;
--enable_result_log

--echo ############
--echo # Verify that all 3 x 9 rows were returned from SPJ:
--echo # - 2 x 9 rows from t1 outer join t2
--echo #   (No t1-match elimination in an outer-join)
--echo # - 9 rows from t1 inner join t3
--echo # -> 27 rows
--echo #
--disable_query_log
--eval select sum(val) - $old_val as SPJ_rows_returned from ndbinfo.counters where block_name="DBSPJ" and counter_name = "SCAN_ROWS_RETURNED"
--enable_query_log

drop table t;


########################################
# Verify counters for entire test:
# Note: These tables are 'temporary' withing 'connection spj'

connection spj;

# Calculate the change in mysqld counters.
select new.variable_name, new.variable_value - old.variable_value
       from server_counts_at_startup as old,
         performance_schema.global_status as new
       where new.variable_name = old.variable_name
       order by new.variable_name;

drop table server_counts_at_startup;

set ndb_join_pushdown = @save_ndb_join_pushdown;

